Самостоятельно удалять объект в С++
Возможный дубликат:
С++: Удалить это?
Объектно-ориентированное самоубийство или удалить это;
Интересно, безопасно ли приведенный ниже код:
#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()
никогда не должна быть достигнута, но ее вызов будет вызван. Разве вы не думаете, что это противоречит языковой философии?