析构函数和'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
用于管理动态内存,但析构函数是class本身的一个方法,当对象从内存(堆栈或堆)中释放时总是调用).为对象释放内存时调用析构函数,以便 if 对象本身处理内存,有时间释放该内存。这就是为什么智能指针很好:
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!
}
内存分配有多种方式,其中一些是:
- 自动内存分配:
在这种情况下,范围内定义的变量(例如函数)是自动分配的,并且通常存储在堆栈中。您对该内存的生命周期有有限的控制。例如:函数中的自动变量仅在函数完成之前存在,然后当超出该范围时,它们的 destructors 会自动调用,即您不能调用 delete 释放为该对象保留的内存。
- 动态内存分配:
在这种情况下,范围内定义的变量(例如函数)是动态分配的。您可以控制这些内存位置的大小和寿命。如果你不释放保留内存(删除它),分配的内存仍然有效并且可以访问,即使函数终止(超出范围)并且在这种情况下你'都会有内存泄漏,这可能会导致程序崩溃。所以这个对象应该是 delete 显式的,这反过来会调用那个对象的 destructor。
就像构造函数只是创建对象过程的部分一样,调用析构函数只是对象创建过程的部分销毁一个对象的过程。这是一个可以放置特殊清理代码的地方,例如关闭文件句柄或销毁其他间接拥有的对象。
delete
是触发删除动态分配对象的方式。其他类型的对象在超出范围时会自动删除。此关键字将清理内存并更抽象地结束对象的生命周期,以便编译器知道它在概念上不再“存在”。
您通常不会手动调用析构函数,因为它通常不足以安全地自行结束对象的生命周期。但是,当您对对象的存在进行超细粒度控制时,这样做很有用,(例如)放置 new
:然后,can 就足够了.但这是一个特例。
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
用于管理动态内存,但析构函数是class本身的一个方法,当对象从内存(堆栈或堆)中释放时总是调用).为对象释放内存时调用析构函数,以便 if 对象本身处理内存,有时间释放该内存。这就是为什么智能指针很好:
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!
}
内存分配有多种方式,其中一些是:
- 自动内存分配:
在这种情况下,范围内定义的变量(例如函数)是自动分配的,并且通常存储在堆栈中。您对该内存的生命周期有有限的控制。例如:函数中的自动变量仅在函数完成之前存在,然后当超出该范围时,它们的 destructors 会自动调用,即您不能调用 delete 释放为该对象保留的内存。 - 动态内存分配:
在这种情况下,范围内定义的变量(例如函数)是动态分配的。您可以控制这些内存位置的大小和寿命。如果你不释放保留内存(删除它),分配的内存仍然有效并且可以访问,即使函数终止(超出范围)并且在这种情况下你'都会有内存泄漏,这可能会导致程序崩溃。所以这个对象应该是 delete 显式的,这反过来会调用那个对象的 destructor。
就像构造函数只是创建对象过程的部分一样,调用析构函数只是对象创建过程的部分销毁一个对象的过程。这是一个可以放置特殊清理代码的地方,例如关闭文件句柄或销毁其他间接拥有的对象。
delete
是触发删除动态分配对象的方式。其他类型的对象在超出范围时会自动删除。此关键字将清理内存并更抽象地结束对象的生命周期,以便编译器知道它在概念上不再“存在”。
您通常不会手动调用析构函数,因为它通常不足以安全地自行结束对象的生命周期。但是,当您对对象的存在进行超细粒度控制时,这样做很有用,(例如)放置 new
:然后,can 就足够了.但这是一个特例。