Удаление указателя в деструкторе C ++ - PullRequest
0 голосов
/ 17 мая 2018

Я использую класс из библиотеки.Пусть это будет A, и у него есть символьный указатель "token"

Мой код:

void someFunction()
{
    A a;
    cout<<a.token;
    anotherFunction(a);
    cout<<a.token;  //  line 4: now token became invalid [1]
}

void anotherFunction(A copyOfA);
{
   //  doing something
}  //  on exit destructor of copyofA will be called

[1] Почему он стал недействительным: класс A выглядит следующим образом:

class A
{
    char *token;
    public:
    A()
    {
        token = GetRandomToken();   // GetRandomToken will return a 'new Char' array
    }
    ~A()
    {
        if(token != NULL)
        {
            delete[] token;    // it is A's responsibility to delete the memory it created
            token = NULL;
        }
    }
};

в anotherFunction, когда деструктор copyOfA называется token удален. Таким образом, в строке 4 токен недопустим, потому что и a.token, и copyOfA.token оба указывают на одно и то жеадрес.

Какое решение, в следующем случае:

case 1: class A находится в данной библиотеке: поэтому я не могу изменить его.

case2: если я смогу изменить class A: Каков будет хороший способ справиться с этим?

Я знаю, если вызовет другую функцию с помощью передачи ссылки, я не столкнусь с этой проблемой.Но что, если в какой-то момент мне нужно будет сохранить копию объекта?

Проверьте пример кода здесь: https://ideone.com/yZa4k4

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

Если ваш пример точен, то class A не имеет надлежащего конструктора копирования и поэтому удаляет токен для обоих экземпляров.Что приводит к двойному удалению, потому что указатель в первом случае не изменился.

0 голосов
/ 17 мая 2018

Если вы не можете изменить class A, вам следует избегать его копирования. Я думаю, что самый безопасный способ сделать это - динамически выделить объект class A:

void anotherFunction(std::shared_ptr<A> aPtr)
{
    // please also note that in your case token is PRIVATE
    std::cout << aPtr->token << std::endl;
}

std::shared_ptr<A> aPtr(new A);
std::cout << aPtr->token << std::endl;
anotherFunction(aPtr);

Или, если вы настаиваете на выделении стека, вы должны изменить anotherFunction подпись на:

void anotherFunction(const A& a)
{
    std::cout << a.token << std::endl;
}

для передачи вашего аргумента по константной ссылке (избегайте копирования-конструктора).

Теперь, если вы МОЖЕТЕ изменить свой class A, вам следует применить правило трех / пяти / нуля , потому что у вас нетривиальный деструктор. Ленивый способ сделать это состоит в том, чтобы просто объявить другие конструкторы как удаленные (тогда, как в вашем примере, вы не можете скопировать ваш объект A, но у вас также есть гарантия, что никто не будет пытаться это сделать):

class A
{
    public:
    // for this example purpose I made token PUBLIC, but it is a bad idea in general
    char *token;
    A()
    {
        token = GetRandomToken();   // GetRandomToken will return a 'new Char' array
    }
    ~A()
    {
        if(token != NULL)
        {
            delete[] token;    // it is A's responsibility to delete the memory it created
            token = NULL;
        }
    }
    A(const A& other) = delete;
    A(A&& other) = delete;
};

Или, если вам не лень, вы можете подумать о том, как скопировать память из указателя token в одном объекте в другой объект - это зависит от вас, как бы вы это реализовали. Это зависит от требований и реализации GetRandomToken.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...