析构函数和'delete'之间的区别
The difference between a destructor and 'delete'
在C++中销毁对象和删除有什么区别?在 OOP 中,当对象超出范围时,将调用析构函数,而在动态分配内存时,我们必须在析构函数中使用delete
关键字。那么,销毁或删除对象意味着什么?
析构函数是class
的特殊方法。每当对象超出范围或有人显式调用它时,都会调用它。
调用对象析构函数但不
删除的示例:struct MyObject
{
MyObject() { std::cout << "default constructor"; }
~MyObject() { std::cout << "destructor"; }
void doWork() {};
}
int main()
{
{
MyObject object; //constructor is called and memory allocated for the object on the stack
object.doWork();
} //at the end of scope, the destructor of MyObject is called, and the stack memory is "released"
// object is not longer available and stack memory is free
}
作用域对您没有帮助的示例:
int main()
{
{
MyObject* object_ptr = new MyObject; //constructor is called and memory allocated on the heap. The pointer_ptr object
object_ptr->doWork();
} //at the end of scope the object_ptr is removed from the stack, but the destructor for the MyObject is not called!
// object_ptr is no longer available.
}
对于上面的例子,我们有一个动态分配的内存问题。我们通过调用 delete 来显式调用我们指向的对象的析构函数(并释放 MyObject 所在的内存!
int main()
{
{
MyObject* object_ptr = new MyObject; //constructor is called and memory allocated on the heap. The pointer_ptr object
object_ptr->doWork();
delete object_ptr; // destructor of MyObject is called and memory freed.
// object_ptr is still usable here, but it is pointing at an destroyed object, so don't use it! (unless you redirect it)
}
}
所以delete
用于管理动态内存,但析构函数是类本身的方法,当对象从内存(堆栈或堆(中释放时,总是调用它。析构函数是在释放对象的内存时调用的,因此,如果对象本身处理内存,则有时间释放该内存。这就是为什么智能指针很好:
int main()
{
{
std::unique_ptr<MyObject> object_ptr = std::make_unique<MyObject>(); //constructor is called and memory allocated on the heap. The pointer_ptr object
object_ptr->doWork();
} //destructor for std::unique_ptr<MyObject> is called, which in turn calls delete on the object it is pointing at, which calls the destructor of that object!
}
有多种内存分配方法,其中一些是:
- 自动内存分配:
在这种情况下,作用域内定义的变量(例如函数(是自动分配的,并且通常存储在堆栈上。您对此内存的生存期的控制有限。例如:函数中的自动变量仅在函数完成之前存在,然后当超出该范围时,会自动调用它们的析构函数,即您不得调用delete来释放为该对象保留的内存。 - 动态内存分配 :
在这种情况下,作用域内定义的变量,例如函数,是动态分配的。您可以控制这些内存位置的大小和生存期。如果不释放保留的内存(删除它(,则分配的内存仍然有效且可访问,即使函数已终止(超出范围(,在这种情况下,您将出现内存泄漏,这可能会导致程序崩溃。因此,应显式删除该对象,这反过来将调用该对象的析构函数。
就像构造函数只是创建对象过程的一部分一样,调用析构函数只是销毁对象过程的一部分。这是一个特殊清理代码可以去的地方,例如关闭文件句柄或销毁其他间接拥有的对象。
delete
是触发动态分配对象的删除的方式。其他类型的对象在超出范围时会自动删除。此关键字将清理内存并更抽象地结束对象的生存期,以便编译器知道它在概念上不再"存在"。
通常不会手动调用析构函数,因为它通常不足以安全地结束对象的生存期。但是,当您对对象的存在进行超细粒度控制时,这样做很有用,例如,放置new
:那么,它可能就足够了。但这是一个特例。
当一个对象被销毁时,它的析构函数被调用。可以删除指向动态分配的内存的指针,但不能删除对象本身(除非您将指针视为一种对象(。
这些操作中的任何一个都可能产生连锁效应,导致其他操作发生(或同一操作的多个实例(。例如,如果删除指向对象的指针,则将调用对象析构函数(如果有(,并且它的析构函数可能会导致删除其他指针并销毁其他对象。
基本上析构函数是关于对象的死亡,删除是关于释放动态分配的内存,但这两个操作通常是交织在一起的。
- C++中std::resize(n)和std::shrink_to_fit之间的区别
- int(c) 和 c-'0' 之间的区别。C++
- C++ 使用 assign 函数的字符串与直接使用 '=' 更改值的字符串之间的区别
- std::atomic和std::condition_variable wait,notify_*方法之间的区别
- 我是C++编程的新手,这些代码之间有什么区别,我应该使用哪一个
- 在 const 函数中通过引用和指针返回之间的区别
- 我想知道长双倍和双倍之间的区别
- 这 4 个 lambda 表达式之间有什么区别?
- 结构体 S { int align; } 之间的区别;(struct 关键字后的名称)和 struct { int al
- (double) 和 double() 之间的区别
- & 和 * 之间的区别
- std::is_convertible 和 std::convertible_to 之间的区别(在实践中)?
- 析构函数和'delete'之间的区别
- 在 typedef 内部使用 const 关键字和在 typedef 外部使用 const 关键字之间有区别吗?
- 从预序遍历构造 bst 的 c++ 和 python 解决方案之间的区别
- vector.back() 和 vector[vector.size() - 1] 之间的区别?
- 空指针常量 (nullptr)、空指针值和空成员指针值之间有什么区别?
- 函数签名与调用的函数不匹配,常量字符[]和字符*之间的区别?
- OpenMP #pragma omp for v/s #pragma omp parallel for 之间的区别?
- S() 与 S{} 之间的区别?