Ошибка при инициализации указателя приводит к нарушению доступа на запись

#c #pointers

#c #указатели

Вопрос:

У меня возникли некоторые проблемы с указателями. У меня есть класс

 class Foo
{
private:
   int var;
public:
   Foo() = default;
   void SetVar(int v) {var = v;}
};
 

на который мне нужно создать указатель в другом классе:

 class Object
{
private:
   Foo* ptr;
public:
   Object() = default;
   void func()
   {
      ptr->SetVar(10);
   }

};
 

Это дает мне нарушение доступа на запись. Я думаю, что проблема связана с инициализацией ptr , но я не знаю, как исправить эту проблему. Спасибо!

Комментарии:

1. Нет инициализации Object::ptr , и в этом проблема. Конструктор по умолчанию недостаточен, и предполагается Object , что предполагается сохранить право собственности на Foo созданный в Object конструкторе, деструктор также не справится с задачей…

2. И не беспокойтесь о таких строках, Foo() = defau< пока не узнаете, зачем (в некоторых случаях) они нужны (опубликованный код этого не делает).

3. Вы инициализировали Foo new или адресом member field ?

4. Вам нужно будет создать объект Foo и указать ptr на него. В зависимости от назначения кода это может быть сделано в разных местах, либо в конструкторе Object , либо внутри func , либо из другой функции

Ответ №1:

Инициализируйте ptr в constructor Object классе, и delete это в destructor ! или использовать smart pointers !

объявленный ptr как

 Foo* ptr = nullptr;
 

добавить определение для Object() as

 Object::Object()
{
    ptr = new Foo();
}
 

и определение для ~Object() as

 Object::~Object()
{
    if (ptr != nullptr)
    {     
        delete ptr;
        ptr = nullptr;
    }
}
 

Комментарии:

1. Я бы предпочел не распределять переменные динамически. Есть ли какой-нибудь способ не делать этого?

2. Я изучал Windows API, где вы пишете такой код: m_pRenderTarget->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), amp;m_pBlackBrush); есть ли способ реализовать этот метод, когда вы передаете ссылку в функцию, которая затем устанавливает ее равной экземпляру, в моем случае?

3. @johndoe В этом коде нет ссылок (или где-либо в Windows API, основанном на C, который не имеет ссылок). Я думаю, вы неправильно amp; понимаете адрес оператора.

4. @johndoe Но, конечно, вы можете написать код, подобный приведенному выше, на C , просто поймите, что он не использует ссылки.

5. Если бы я попытался сделать что-то подобное, как бы я сохранил объект от уничтожения?

Ответ №2:

Я думаю, что проблема связана с инициализацией ptr

Можно и так сказать. Вам не удалось инициализировать указатель перед косвенным обращением через указатель для доступа к объекту, на который не указывается.

Я не знаю, как исправить эту проблему.

Шаг 1: Создайте объект типа Foo .

Шаг 2: Инициализируйте указатель адресом объекта, созданного на шаге 1.

Шаг 3 и далее: Убедитесь, что созданный объект остается в живых по крайней мере до тех пор, пока указатель.

Минимальный пример:

 class Object
{
    // ...
    explicit Object(Foo* ptr): ptr(ptr) {}; // Step 2


// usage
Foo f; // Step 1
{
    Object o{amp;f};
    o.func();
} // step 3
 

Я рекомендую рассмотреть альтернативный дизайн, в котором вы сохраняете Foo объект как объект-член, а не указываете на объект, хранящийся в другом месте.

Комментарии:

1. Возможно ли в этой ситуации использовать std::unique_ptr?

2. @johndoe Возможно, уре. Но зачем использовать динамическое распределение, если оно вам не нужно?