由于删除运算符会释放内存,为什么需要析构函数?
来自 C++ 常见问题解答: http://www.parashift.com/ c++-faq-lite/dtors.html#faq-11.9
记住:delete p 做了两件事:调用析构函数并释放内存。
如果delete释放了内存,那么这里还需要析构函数吗?
From c++ FAQ: http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.9
Remember: delete p does two things: it calls the destructor and it deallocates the memory.
If delete deallocates the memory, then what's the need of the destructor here?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
除了关注在堆上分配的对象(使用 new ;仅使用删除来释放)的答案之外......不要忘记,如果您放置对象在堆栈上(因此,不使用new),它的析构函数将被自动调用,并且将从堆栈中删除(不调用delete ) 当它超出范围时。因此,当对象超出范围时,您有一个保证执行的函数,并且这是执行对象分配的所有其他资源(各种句柄、套接字...和由该对象在堆上创建的对象 - 如果它们不能比该对象存活得更久)。这用于 RAII 习惯用法。
In addition to answers focused on the objects allocated on the heap (with new; which are deallocated only with delete)...Don't forget that if you place the object on the stack (so, without using new), its destructor will be called automatically and it will be removed from the stack (without calling delete) when it goes out of scope. So you have one function that is guaranteed to be executed when object goes out of the scope and that is perfect place to perform cleanup of all other resources allocated by the object (various handles, sockets...and objects created on the heap by this object - if they must not outlive this one). This is used in the RAII idiom.
析构函数的要点是在对象之后执行清理所需的任何逻辑,例如:
The point of the destructor is to execute any logic required to clean up after your object, for example:
如果除了取消分配内存之外还需要执行其他操作,则需要调用析构函数。
除了非常简单的类之外,通常还有其他类。
例如关闭文件句柄或关闭数据库连接、删除对象中的成员数据指向的其他对象等等。
一个经典的例子是堆栈的实现:
现在想想如果每次删除一个堆栈时都没有调用析构函数会发生什么。在这种情况下,C++ 中没有自动垃圾回收,因此 stackData 内存会泄漏,最终会耗尽。
析构函数删除其所有资源的要求沿着树向下移动到基本类型。例如,您可能有一个包含数据库连接数组的数据库连接池。其析构函数将
删除
每个单独的数据库连接。单个数据库连接可能会分配很多东西,例如数据缓冲区、缓存、编译的 SQL 查询等。因此数据库连接的析构函数也必须
删除
所有这些东西。换句话说,您有类似的情况:
释放数据库连接池的内存不会影响单个数据库连接或它们指向的其他对象的存在。
这就是为什么我提到只有简单的类可以在没有析构函数的情况下逃脱,而这些类往往出现在上面那棵树的底部。
像这样的类
并不真正需要析构函数,因为您需要做的就是内存释放。
最重要的是,
new
和delete
是同一极的两端。调用 new 首先分配内存,然后调用相关的构造函数代码以使对象处于可工作状态。然后,当您完成后,
delete
调用析构函数来“拆除”您的对象,并回收为该对象分配的内存。You need to call the destructor in case there are other things that need to be done other than just de-allocating memory.
Other than very simple classes, there usually are.
Things like closing file handles or shutting down database connections, deleting other objects that are pointed to by members data within your object, and so forth.
A classic example is the implementation of a stack:
Now think of what would happen if the destructor was not called every time one of your stacks got deleted. There is no automatic garbage collection in C++ in this case so the
stackData
memory would leak and you'd eventually run out.This requiring of a destructor to delete all its resources moves down the tree towards the basic types. For example, you may have a database connection pool with an array of database connections. The destructor for that would
delete
each individual database connection.A single database connection may allocate a lot of stuff, such as data buffers, caches, compiled SQL queries and so on. So a destructor for the database connection would also have to
delete
all those things.In other words, you have something like:
Freeing the memory for the DB connection pool would not affect the existence of the individual DB connection or the other objects pointed to by them.
That's why I mentioned that only simple classes can get away without a destructor, and those are the classes that tend to show up at the bottom of that tree above.
A class like:
has no real need for a destructor since the memory deallocation is all you need to do.
The bottom line is that
new
anddelete
are opposite ends of the same pole. Callingnew
first allocates the memory then calls the relevant constructor code to get your object in a workable state.Then, when you're done,
delete
calls the destructor to "tear down" your object the reclaims the memory allocated for that object.假设您有一个动态分配内存的类:
现在让我们动态分配一个
something
对象:现在,如果
delete
没有调用析构函数,那么s- >p
永远不会被释放。因此,删除必须调用析构函数,然后释放内存。Suppose you have a class that dynamically allocates memory:
Now let's dynamically allocate a
something
object:Now, if the
delete
didn't call the destructor, thens->p
would never be freed. Sodelete
has to both call the destructor and then deallocate the memory.析构函数负责释放除对象分配的内存之外的资源。例如,如果对象打开了一个文件句柄,则析构函数可以对其调用
fclose
。The destructor is in charge of freeing resources other than the object's allocated memory. For instance, if the object has a file handle open, the destructor could call
fclose
on it.它释放该对象占用的内存。但是,对象分配的任何内容(以及该对象拥有的内容)都需要在析构函数中处理。
另外,一般来说...常见问题解答...通常不会错。
It deallocates the memory taken up by that object. However, anything that has been allocated by the object (and owned by that object) needs to be taken care of in the destructor.
Also, in general ... FAQs ... usually not wrong.
如果您声明一个普通类(而不是指针),它会在程序关闭时自动调用构造函数并自动调用析构函数。如果您声明为指针,它会在使用 new 初始化时调用构造函数,并且不会自动调用析构函数,直到您使用 delete 调用删除该指针
if you declare a class normal (not pointer), it automatically calls constructor and call destructor automatically when the program closes. If you declare as pointer, it call the constructor when initializes using new and does not call destructor automatically until you call delete that pointer using delete
析构函数的作用是清除对象构造函数和成员函数可能对程序状态所做的更改。这可以是任何东西 - 从某个全局列表中删除对象、关闭打开的文件、释放分配的内存、关闭数据库连接等。
The destructor is there to clean up the changes that the object constructor and member functions might have done to the program state. That can be anything - remove the object from some global list, close an opened file, free allocated memory, close a database connection, etc.
析构函数不会是一个强制功能。 C、Java、C# 等语言没有析构函数。 C++ 没有它也可以生存。
析构函数是 C++ 提供的一种特殊工具(与构造函数相同)。它当对象被“销毁”时调用。
销毁意味着,对象作用域正式结束,任何对该对象的引用都将是非法的。例如:
在上面的代码中,
obj
是创建的A
类型的static
数据;foo()
返回对obj
的引用,这是可以的,因为obj.~A()
尚未被调用。假设 obj 是非静态的。代码将编译,但是,foo()
返回的A*
现在指向一个不再是A
对象的内存位置。意思是->操作错误/非法。现在,您应该能够区分内存的释放和对象的销毁。两者紧密结合,但有一线之隔。
另请记住,析构函数可以在多个位置调用:
在上面的示例中,
obj.~A()
将仅调用一次,但可以从所示的任何位置调用它。在破坏过程中,您可能想做一些有用的事情。假设A类在对象销毁时计算出一些结果;它应该打印计算结果。它可以用
C
风格的方式完成(在每个return
语句中放置一些函数)。但~A()
是一个随时可用的一站式工具。The destructor would not have been a mandatory feature. The languages like, C, Java, C# don't have destructors. C++ also can live without it.
Destructor is a special facility provided by C++ (same as Constructor). It's called when an object is "destroyed".
Destroy means, the object scope is officially finished and any reference to that object will be illegal. For example:
In above code,
obj
is astatic
data created of typeA
;foo()
returns a reference to thatobj
which is ok, becauseobj.~A()
is not yet called. Supposeobj
is non-static. The code will compile, however,A*
returned byfoo()
is now pointing to a memory location which is no more anA
object. Means -> the operation is bad/illegal.Now, you should be able to distinguish between deallocation of the memory and the destruction of the object. Both are tightly coupled, but there is a thin line.
Also remember that destructor can be called at multiple places:
In above example,
obj.~A()
will be called only once, but it can be called from any of the places shown.During the destruction, you may want to do some useful stuff. Suppose
class A
calculates some result, when the object destroys; it should print the result of calculation. It can be done inC
style way (putting some function at everyreturn
statement). But~A()
is a readily available one-stop facility.