C++ - 析构函数只是释放内存还是实际上删除了对象?
C++ - Does the Destructor just deallocate the memory or does it actually delete the object?
为了检查这个,我有 运行 这个小测试代码。
#include <iostream>
using namespace std;
class name {
public:
int data;
name(int data) {
this->data = data;
}
void printData() {
cout << data << endl;
}
};
int main() {
name* namePointer;
{
name n(5);
namePointer = &n;
}
namePointer->printData();
}
那么,两个问题:
name
对象n
是在main
里面的block里面创建的,并且保存了它的指针,确保我们出来的时候会调用它的析构函数的块。但是指针指向同一个对象,它的成员函数仍然可以访问。这不是说对象还没有删除吗?
假设我将此添加到我的 name
class:
~name() {
cout << "destructor called" << endl;
}
重写析构函数而不在其中执行任何操作(此处为 ~name()
)是否会阻止对象被删除?
编辑:感谢您的回复,它真的很有帮助。但我可以知道这些反对票的原因吗,我认为这是一个非常好的问题。 ¯_(ツ)_/¯
在该块之后使用 namePointer
是未定义的行为,因为它是 dangling pointer。之后它的行为(正确或错误)可能会在不同的机器、编译器等上发生变化。
覆盖析构函数以输出一些文本不会改变对象的内存仍然被释放的事实。所以在这种情况下 n
的析构函数将在块的末尾被调用,这将删除对象及其成员变量。
在 C++ 中,两个独立的概念是 'object lifetime' 和 'storage duration'。持续时间与生命周期几乎相同,但标准在这里使用两个不同的词。存储是指对象占用的物理内存,而对象生命周期是指允许访问对象的时间。
考虑到这一点,一个人有两个理解构造函数和析构函数决定对象的生命周期——在调用构造函数之前和调用析构函数之后不允许访问对象,并且不要说任何关于存储生命周期的事情。很明显,存储持续时间(或生命周期)不应小于对象生命周期——一旦不能访问没有物理表示的对象——但可以长于它。
当 placement new
与显式析构函数调用一起使用时很容易看出 - 存储仍然可用,但对象已经消失。
Does the Destructor just deallocates the memory or actually deletes the object
析构函数调用子对象的析构函数(如果有),执行析构函数体(如果定义了)。从技术上讲,释放内存的不是析构函数。可以在不释放的情况下调用析构函数,并且可以在不调用析构函数的情况下释放内存。
当使用运算符delete
删除动态对象时,会调用析构函数,然后释放内存。同样,当一个自动变量(比如你的n
)的生命周期结束时,它的析构函数被调用,内存被释放。
不清楚您所说的 "deletes the object" 是什么意思。析构函数永远不会调用 delete
运算符(除非析构函数的主体 {,of a sub object} sub object 调用 delete
运算符,但它不是 this
被删除) .
如果你的意思是析构函数是否销毁对象,则相反:当一个对象被销毁时,它的析构函数将被调用。
- ... But the pointer points to the same object
指针指向对象所在的位置。该对象已被销毁,不再存在。
... and its member functions are still accessible.
成员函数的可访问性不取决于所指向的内容。取消引用不指向对象的指针(包括调用成员函数)具有未定义的行为。
Doesn't this mean that the object isn't deleted yet?
没有。你不能从未定义的行为中得出结论。
- Does overriding the destructor function ...
这不是覆盖。覆盖是一个特定的语言术语,涉及继承和虚函数。
你所做的是定义一个析构函数。
- ... and doing nothing in it (here in ~name()), prevent the object from being deleted?
没有。在析构函数的主体中什么也不做与隐式析构函数所做的完全相同(当您未定义析构函数时对象所具有的那个)。它没有 "prevent the object form being deleted".
1 ... Doesn't this mean that the object isn't deleted yet?
没有
2 ... Does overriding the destructor function, and doing nothing in it (here > in ~name()), prevent the object from being deleted?
没有
cout 是你的朋友。
这是我的代码版本(我已经应用了我的名称编码标准)
#include <iostream>
class Name_t
{
int m_data;
public:
Name_t(int data) : m_data(data) {
std::cout << "\n Name_t::ctor" << std::endl;
}
~Name_t() {
std::cout << "\n Name_t::dtor" << std::endl;
}
void cout() { std::cout << "\n Name_t.cout() "
<< m_data << std::endl; }
};
class T517_t
{
public:
T517_t() = default;
~T517_t() = default;
int exec()
{
Name_t* Name_tPointer = nullptr;
{
Name_t n(5);
Name_tPointer = &n;
}
Name_tPointer->cout();
return(0);
}
}; // class T517_t
int main(int , char** )
{
int retVal = -1;
{
T517_t t517;
retVal = t517.exec();
}
return(retVal);
}
运行 这个,你在 UB(未定义的行为)之前看到 ctor 和 dtor 运行。
Name_t::ctor
Name_t::dtor
Name_t.cout() 5
另一个指示器(通过 cout)是清除或使 dtor 中的数据无效......我很少这样做,除非在诊断期间。
用
替换dtor
~Name_t() {
m_data = -1;
std::cout << "\n Name_t::dtor" << std::endl;
}
可以看到 dtor 已使您的数据无效。
Name_t::ctor
Name_t::dtor
Name_t.cout() -1
Does destructor deallocate memory?
哪个内存?
否 - 对象的 dtor 不释放对象。
是 - 对象的 dtor 应该释放在 ctor(Ying 和 Yang)中分配的任何内存,除非已经被实例的其他方法删除。
为了检查这个,我有 运行 这个小测试代码。
#include <iostream>
using namespace std;
class name {
public:
int data;
name(int data) {
this->data = data;
}
void printData() {
cout << data << endl;
}
};
int main() {
name* namePointer;
{
name n(5);
namePointer = &n;
}
namePointer->printData();
}
那么,两个问题:
name
对象n
是在main
里面的block里面创建的,并且保存了它的指针,确保我们出来的时候会调用它的析构函数的块。但是指针指向同一个对象,它的成员函数仍然可以访问。这不是说对象还没有删除吗?假设我将此添加到我的
name
class:~name() { cout << "destructor called" << endl; }
重写析构函数而不在其中执行任何操作(此处为
~name()
)是否会阻止对象被删除?
编辑:感谢您的回复,它真的很有帮助。但我可以知道这些反对票的原因吗,我认为这是一个非常好的问题。 ¯_(ツ)_/¯
在该块之后使用 namePointer
是未定义的行为,因为它是 dangling pointer。之后它的行为(正确或错误)可能会在不同的机器、编译器等上发生变化。
覆盖析构函数以输出一些文本不会改变对象的内存仍然被释放的事实。所以在这种情况下 n
的析构函数将在块的末尾被调用,这将删除对象及其成员变量。
在 C++ 中,两个独立的概念是 'object lifetime' 和 'storage duration'。持续时间与生命周期几乎相同,但标准在这里使用两个不同的词。存储是指对象占用的物理内存,而对象生命周期是指允许访问对象的时间。
考虑到这一点,一个人有两个理解构造函数和析构函数决定对象的生命周期——在调用构造函数之前和调用析构函数之后不允许访问对象,并且不要说任何关于存储生命周期的事情。很明显,存储持续时间(或生命周期)不应小于对象生命周期——一旦不能访问没有物理表示的对象——但可以长于它。
当 placement new
与显式析构函数调用一起使用时很容易看出 - 存储仍然可用,但对象已经消失。
Does the Destructor just deallocates the memory or actually deletes the object
析构函数调用子对象的析构函数(如果有),执行析构函数体(如果定义了)。从技术上讲,释放内存的不是析构函数。可以在不释放的情况下调用析构函数,并且可以在不调用析构函数的情况下释放内存。
当使用运算符delete
删除动态对象时,会调用析构函数,然后释放内存。同样,当一个自动变量(比如你的n
)的生命周期结束时,它的析构函数被调用,内存被释放。
不清楚您所说的 "deletes the object" 是什么意思。析构函数永远不会调用 delete
运算符(除非析构函数的主体 {,of a sub object} sub object 调用 delete
运算符,但它不是 this
被删除) .
如果你的意思是析构函数是否销毁对象,则相反:当一个对象被销毁时,它的析构函数将被调用。
- ... But the pointer points to the same object
指针指向对象所在的位置。该对象已被销毁,不再存在。
... and its member functions are still accessible.
成员函数的可访问性不取决于所指向的内容。取消引用不指向对象的指针(包括调用成员函数)具有未定义的行为。
Doesn't this mean that the object isn't deleted yet?
没有。你不能从未定义的行为中得出结论。
- Does overriding the destructor function ...
这不是覆盖。覆盖是一个特定的语言术语,涉及继承和虚函数。
你所做的是定义一个析构函数。
- ... and doing nothing in it (here in ~name()), prevent the object from being deleted?
没有。在析构函数的主体中什么也不做与隐式析构函数所做的完全相同(当您未定义析构函数时对象所具有的那个)。它没有 "prevent the object form being deleted".
1 ... Doesn't this mean that the object isn't deleted yet?
没有
2 ... Does overriding the destructor function, and doing nothing in it (here > in ~name()), prevent the object from being deleted?
没有
cout 是你的朋友。
这是我的代码版本(我已经应用了我的名称编码标准)
#include <iostream>
class Name_t
{
int m_data;
public:
Name_t(int data) : m_data(data) {
std::cout << "\n Name_t::ctor" << std::endl;
}
~Name_t() {
std::cout << "\n Name_t::dtor" << std::endl;
}
void cout() { std::cout << "\n Name_t.cout() "
<< m_data << std::endl; }
};
class T517_t
{
public:
T517_t() = default;
~T517_t() = default;
int exec()
{
Name_t* Name_tPointer = nullptr;
{
Name_t n(5);
Name_tPointer = &n;
}
Name_tPointer->cout();
return(0);
}
}; // class T517_t
int main(int , char** )
{
int retVal = -1;
{
T517_t t517;
retVal = t517.exec();
}
return(retVal);
}
运行 这个,你在 UB(未定义的行为)之前看到 ctor 和 dtor 运行。
Name_t::ctor
Name_t::dtor
Name_t.cout() 5
另一个指示器(通过 cout)是清除或使 dtor 中的数据无效......我很少这样做,除非在诊断期间。
用
替换dtor ~Name_t() {
m_data = -1;
std::cout << "\n Name_t::dtor" << std::endl;
}
可以看到 dtor 已使您的数据无效。
Name_t::ctor
Name_t::dtor
Name_t.cout() -1
Does destructor deallocate memory?
哪个内存?
否 - 对象的 dtor 不释放对象。
是 - 对象的 dtor 应该释放在 ctor(Ying 和 Yang)中分配的任何内存,除非已经被实例的其他方法删除。