Самостоятельно удалять объект в С++

Возможный дубликат:
С++: Удалить это?
Объектно-ориентированное самоубийство или удалить это;

Интересно, безопасно ли приведенный ниже код:

#include <iostream>
using namespace std;

class A
{
public:
    A() {
        cout << "Constructor" << endl;
    }
    ~A() {
        cout << "Destructor" << endl;
    }

    void deleteMe() {
        delete this;
        cout << "I was deleted" << endl;
    }
};

int main()
{
    A *a = new A();
    a->deleteMe();
    cout << "Exit ...";
    return 0;
}

Выход:

Constructor
Destructor
I was deleted
Exit ...

и нормально выходить из программы, но есть ли здесь некоторые нарушения доступа к памяти?

Ответ 1

Это нормально для delete this, если никто не будет использовать объект после этого вызова. И в случае, если объект был выделен на кучу, конечно

Например, движок игры cocos2d-x делает это. Он использует ту же схему управления памятью, что и Objective-C, и вот метод базового объекта:

void CCObject::release(void)
{
    CCAssert(m_uReference > 0, "reference count should greater than 0");
    --m_uReference;

    if (m_uReference == 0)
    {
        delete this;
    }
}

Я не думаю, что это способ управления памятью c++, но возможно

Ответ 2

Это нормально, потому что у вас есть простой метод. После удаления все переменные и виртуальная таблица будут понятны. Просто проанализируйте этот пример:

#include <iostream>

class foo
{
public:
    int m_var;
    foo() : m_var(1)  
    {

    }

    void deleteMe()
    {
        std::cout << m_var << "\n";
        delete this;
        std::cout << m_var << "\n"; // this may be crush program, but on my machine print "trash" value, 64362346 - for example
    }

    virtual void bar()
    {
        std::cout << "virtual bar()\n";
    }



  void anotherSimpleMethod()
    {
       std::cout << "anotherSimpleMethod\n";
    }

    void deleteMe2()
    {
        bar();
        delete this;
        anotherSimpleMethod();
        // bar(); // if you uncomment this, program was crashed, because virtual table was deleted
    }
};

int main()
{
    foo * p = new foo();
    p->deleteMe();
    p = new foo();
    p->deleteMe2();
    return 0;
}

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

Ответ 3

Абсолютно, вы просто запускаете деструктор. Методы не принадлежат объекту, поэтому он работает нормально. Во внешнем контексте объект (* a) будет уничтожен.

Ответ 4

Если вы сомневаетесь в том, что странные вещи, происходящие в плане использования памяти (или аналогичные проблемы), основаны на правильных инструментах анализа, которые помогут вам в выяснении ситуации.

Например, используйте valgrind или аналогичную программу, чтобы проверить, есть ли утечки памяти или подобные проблемы, которые компилятор может вряд ли вам поможет.

В то время как каждый инструмент имеет свои ограничения, часто можно получить ценную информацию, используя его.

Ответ 5

В нем нет нарушения доступа к памяти, вам просто нужно быть осторожным. Но удаление указателя this вообще не рекомендуется на любом языке, даже если код выше будет работать нормально. Поскольку это так же, как delete a, но попробуйте сделать это другим способом, безопасным способом.

Например, в вашем опубликованном коде есть что-то нелогичное.

void deleteMe() 
{
    delete this;
    cout << "I was deleted" << endl; // The statement here doesn't make any sense as you no longer require the service of object a after the delete operation 
}

EDIT: Для Sjoerd

Выполнение этого способа имеет смысл

 void deleteMe() 
{
    delete this;
}

 int main()
 {
 A *a = new A();
 a->deleteMe();
 cout << "a was deleted" << endl;
 cout << "Exit ...";
 return 0;
 }

Вторая строка в вашей функции deleteMe() никогда не должна быть достигнута, но ее вызов будет вызван. Разве вы не думаете, что это противоречит языковой философии?