我正在学习C ++中的内存管理,但我不明白为什么在离开范围时只调用了一些析构函数。在下面的代码中,当myfunc结束时,只调用obj1析构函数,而不是动态分配的obj2。
int myfunc (cl1 *oarg) {
cout << "myfunc called" << std::endl;
cl1 obj1(222,"NY");
cl1 *obj2;
obj2= new cl1;
oarg->disp();
obj2 -> ~cl1 ;
}
这是我的析构函数:
cl1 :: ~cl1 () {
std::cout<< " cl1 destructor called"<<std::endl;
std::cout << this->data << std::endl; //just to identify the obj
delete [] str;
str = NULL ;
};
答案 0 :(得分:6)
如果使用new
obj2= new cl1;
然后,除非你在其上调用delete
,否则不会隐式调用它的析构函数。
当作用域结束时,会隐式清除堆栈上的变量(通过调用它们的析构函数)。
不会隐式清除动态分配的对象,用户有责任清除它们,并显式调用delete
。
这就是不应该使用原始指针但使用智能指针的原因。
答案 1 :(得分:2)
动态分配的对象您的责任 - 您需要显式清理它们。当示波器退出时,自动对象(例如obj1
)将被清除,自动。在这种情况下,在范围退出之前 - 显式调用delete obj2
。注意:这一行obj2 -> ~cl1
- 没有做任何事情 - delete
将负责正确触发析构函数。
答案 2 :(得分:2)
obj1
是cl1
类型的对象,自动存储持续时间(它在堆栈上分配,其生命周期由其所在的范围决定)
obj1
是cl1*
类型的对象。也就是说,它是一个指针。指针也有自动存储持续时间,但它指向的对象没有。它指向免费存储中的动态分配对象。
当您离开范围时,具有自动存储持续时间的对象将被销毁。 obj1
被破坏,调用你的析构函数。 obj2
也会被销毁,但obj2
不属于cl1
类型,因此它不会调用cl1
的析构函数。它是一个指针,当它被销毁时它没有什么特别的。
指针不拥有它们指向的对象,因此它们不会做任何事情来确保指向的对象被破坏或清理。 (如果你想要一个“拥有”指针,那就是智能指针类的用途)
考虑到您可以轻松地将多个指针指向同一个对象。
如果指针自动删除了它指向的对象,则会导致错误。两个不同指针指向的对象将被删除两次。
答案 3 :(得分:1)
obj2 -> ~cl1 ;
不要这样做!请改用delete obj2;
。
<强>附录强>
你要做的是明确地调用析构函数。您的代码不会这样做。您的代码获取析构函数的地址,然后将其放入位桶。你的代码是无操作的。显式调用析构函数的正确方法是obj2->~cli();
。
明确地调用析构函数通常是你不应该做的事情。
您应该删除new
创建的内存。正确的方法是使用delete
运算符。这会自动调用析构函数和释放内存。析构函数不释放内存。未能使用删除会导致内存泄漏。
答案 4 :(得分:1)
当在堆栈上创建的对象超出范围时,会自动调用析构函数。
使用动态分配的对象,您需要调用delete obj
。删除会自动为您调用析构函数。
答案 5 :(得分:0)
您应该使用delete
来动态分配对象:
delete obj2;
这会调用析构函数并释放内存。使用智能指针管理此类对象会更好 - 即使在delete
和new
之间抛出异常,他们也会为您调用delete
。
答案 6 :(得分:0)
首先,你应该使用delete
运算符来描述一个对象,而不是直接调用它的析构函数。其次,通过执行new
,你告诉编译器你不想要在它超出范围时删除它。在这种情况下,您需要明确地delete objj2;
删除对象。
答案 7 :(得分:0)
使用std :: unique_ptr或std :: shared_ptr而不是原始指针。 这是避免内存泄漏或双重释放的最佳方法。
这是现代C ++中的正确方法。
int myfunc (cl1 *oarg)
{
cout << "myfunc called" << std::endl;
cl1 obj1(222,"NY");
std::unique_ptr<cl1> obj2( new cl1 );
oarg->disp();
}