显式调用析构函数不会破坏我的对象,为什么?

发布于 2024-12-04 01:20:40 字数 566 浏览 1 评论 0原文

我正在调用析构函数来释放内存,但它并没有删除我的对象。其背后的原因是什么?

我的代码是这样的:

class A
{
public: 
    int a;
    A()
    {
        cout << "a" << endl;
    }
};

class B :public A
{
public: 
    int b;
    B()
    {
        cout << "b" << endl; a = 10; b = 20;
    }
    ~B()
    {
        cout << a << b << endl;
    }
};

我使用它的方式如下:

int main()
{
    {
        B b;
        b.~B();
        b.b=100;  // why this step is executed?
    }
    int x;
    cin>>x;
    return 0;
}

I'm calling the destructor to deallocate memory but it is not deleting my object. What is the reason behind it?

my code is like this:

class A
{
public: 
    int a;
    A()
    {
        cout << "a" << endl;
    }
};

class B :public A
{
public: 
    int b;
    B()
    {
        cout << "b" << endl; a = 10; b = 20;
    }
    ~B()
    {
        cout << a << b << endl;
    }
};

and I am using it like:

int main()
{
    {
        B b;
        b.~B();
        b.b=100;  // why this step is executed?
    }
    int x;
    cin>>x;
    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

夜夜流光相皎洁 2024-12-11 01:20:40

我调用析构函数来释放内存

为什么?在语言级别,析构函数不会释放对象本身占用的内存。

重要的析构函数会结束对象的生命周期,但不会结束对象的存储持续时间。这意味着内存仍然被分配,它只是变成“原始”(未初始化)。
所以,从这个意义上说,它正在破坏你的对象。

同时,一个普通的析构函数根本没有任何作用。即使您显式调用它,对象的生命周期也不会结束。

在你的例子中,析构函数 B::~B 是不平凡的,这正式意味着通过调用它你结束了对象的生命周期。你可以像破坏一个本地对象一样破坏它。 但记忆依然存在。尝试将内存作为 B 对象访问只会导致未定义的行为。

事实上,没有办法手动释放本地对象占用的内存。本地内存始终会自动释放。

i m calling destructor to deallocate memory

Why? At language level destructor does not deallocate memory occupied by the object itself.

A non-trivial destructor ends object's lifetime, but it doesn't end the object's storage duration. This means that memory remains allocated, it just becomes "raw" (uninitialized).
So, in that sense it is destroying your object.

Meanwhile, a trivial destructor has no effect at all. Even if you call it explicitly, the object's lifetime does not end.

In your case the destructor B::~B is non-trivial though, which formally means that by calling it you ended your object's lifetime. You destroyed it as much a local object can be destroyed. But the memory remains. Attempting to access that memory as a B object simply leads to undefined behavior.

In fact, there's no way to manually deallocate memory occupied by a local object. Local memory is always deallocated automatically.

九厘米的零° 2024-12-11 01:20:40

不会这样调用析构函数(嗯,您可以,但通常不会这样做)。

对于像 b 这样的自动变量,当变量超出范围时,将在某个时刻调用析构函数。您不需要显式调用析构函数。

对于使用new在堆上分配的对象,析构函数将在您删除之后被调用。在这种情况下,您也不会显式调用析构函数。

C++03 在 12.4 析构函数 中声明:

隐式调用析构函数:

  • 对于在程序终止时具有静态存储持续时间(3.7.1)的构造对象;
  • 对于具有自动存储持续时间(3.7.2)的构造对象,当创建该对象的块存在时;
  • 对于构造的临时对象,当临时对象的生命周期结束时;
  • 对于由 new 表达式分配的构造对象,通过使用删除表达式;
  • 在多种情况下,由于异常的处理。

析构函数也可以显式调用。

注意:很少需要显式调用析构函数。此类调用的一种用途是使用带有放置选项的 new 表达式将对象放置在特定地址。这种对对象的显式放置和销毁的使用可能是处理专用硬件资源和编写内存管理设施所必需的。

尤其不要做您想要做的事情,因为析构函数将被调用两次,一次由您显式调用,一次当b超出范围时隐式调用。来自标准的同一部分:

一旦为对象调用析构函数,该对象就不再存在;如果为生命周期已结束的对象调用析构函数,则行为未定义。示例:如果显式调用自动对象的析构函数,并且随后以通常会调用对象的隐式销毁的方式保留块,则行为未定义。

这段文本在我掌握的最新 C++11 草案(n3225,2010 年 11 月)中保持不变,并且在 2011 年 8 月批准之前不太可能发生本质变化。

You do not call a destructor like that (well, you can but it's generally not done).

For automatic variables like your b, the destructor will be called at some point when the variable goes out of scope. You don't ever need to call the destructor explicitly.

For objects allocated on the heap with new, the destructor will be called after you delete them. In this case, you also don't call the destructor explicitly.

C++03 states in 12.4 Destructors:

Destructors are invoked implicitly:

  • for a constructed object with static storage duration (3.7.1) at program termination;
  • for a constructed object with automatic storage duration (3.7.2) when the block in which the object is created exits;
  • for a constructed temporary object when the lifetime of the temporary object ends;
  • for a constructed object allocated by a new-expression, through use of a delete-expression;
  • in several situations due to the handling of exceptions.

Destructors can also be invoked explicitly.

Note: explicit calls of destructors are rarely needed. One use of such calls is for objects placed at specific addresses using a new-expression with the placement option. Such use of explicit placement and destruction of objects can be necessary to cope with dedicated hardware resources and for writing memory management facilities.

You especially don't do what you're trying to do since the destructor will be called twice, once explicitly by you and once implicitly when b goes out of scope. From that same section of the standard:

Once a destructor is invoked for an object, the object no longer exists; the behavior is undefined if the destructor is invoked for an object whose lifetime has ended. Example: if the destructor for an automatic object is explicitly invoked, and the block is subsequently left in a manner that would ordinarily invoke implicit destruction of the object, the behavior is undefined.

This text remains unchanged in the latest draft of C++11 that I have (n3225, November 2010) and it's unlikely it would have changed in essence between that and approval in August 2011.

白日梦 2024-12-11 01:20:40

你所做的实际上是调用未定义的行为......仅仅因为你调用了析构函数,并不意味着内存被清零或必然“回收”并且无法访问(特别是在分配了自动变量的情况下)在堆栈上而不是堆上)。可能是这样,但这取决于实现,并且通常由于性能原因而不会这样做,这通常是首先使用 C++ 的原因。因此,理论上您可以在调用析构函数后访问对象占用的内存地址处的值...但同样,这是未定义的行为,您可能会遇到从分段错误到损坏内存的无提示错误的几乎任何情况其他地方等等

What you're doing is actually invoking undefined behavior ... just because you've called the destructor, does not mean that the memory is zeroed out or necessarily "reclaimed" and inaccessable (especially in the case of an automatic variable that was allocated on the stack and not the heap). It could be, but that is left up to the implementation, and typically that is not done due to performance reasons, which is typically the reason for using C++ in the first place. Therefore you can theoretically access the values at the memory address that the object was occupying after calling the destructor ... but again, it's undefined behavior, and you can run into pretty much anything from a segmentation fault, to a silent error that corrupts memory somewhere else, etc.

二手情话 2024-12-11 01:20:40

被执行是因为编写了表示你希望它发生的代码。编译器只是做你告诉它做的事情。

您正在做的事情可能不会像您建议的那样“释放内存”。相反,它只是调用析构函数。析构函数不会释放它们所调用的对象所占用的内存。它们释放对象分配的内存(例如通过调用成员变量的析构函数,或者在其他事情上调用freedelete),但对象本身的内存被释放在其他地方,可以通过 delete 语句的内部工作方式,或者通过编译器清理自动变量(这就是您的 B b 声明所代表的内容)。即使作用域块的关闭也可能不会为 b 释放任何内存;编译器通常会计算出整个子例程需要多少堆栈空间,并在进入时将其全部分配。 B 对象占用的内存在进入内部作用域时为 b 保留,退出时会自动调用析构函数。

It's executed because you wrote the code that said you wanted it to happen. The compiler is simply doing what you told it to do.

What you're doing probably doesn't "deallocate memory," as you suggested it would. Instead, it just calls the destructor. Destructors don't deallocate the memory occupied by the objects they're called on. They deallocate memory allocated by the object (such as by calling destructors of member variables, or calling free or delete on other things), but the memory of the object itself is deallocated elsewhere, either by the internal workings of the delete statement, or by the compiler when cleaning up automatic variables (which is what your B b declaration represents). Even the closing of the scope block probably doesn't deallocate any memory for b; compilers usually figure out how much stack space they'll need for an entire subroutine and allocate it all upon entry. The memory occupied by that B object is reserved for b upon entry to the inner scope, and upon exit, the destructor is called automatically.

两人的回忆 2024-12-11 01:20:40

您的对象已被销毁,但其内存空间仍然存在,直到它超出范围。

Your object has been destroyed but its memory space is still around until it goes out of scope.

一片旧的回忆 2024-12-11 01:20:40

为什么不呢?您的对象已被销毁,但其内存空间仍然存在,直到它超出范围,顺便说一下,它将再次被销毁。做你所做的事情是未定义的行为。

Why wouldn't? Your object has been destroyed but its memory space is still around until it goes out of scope, where it will be destroyed again by the way. It's undefined behavior to do what you do.

唔猫 2024-12-11 01:20:40

析构函数并不是为了显式调用它们而设计的。基本上它只是类的另一种(特殊)方法。
如果你想取消初始化你的对象,然后仍然能够使用它,你可以创建我们自己的方法:

class B: public A
{
public:
 int b;
 B() {cout<<"b"<<endl;a=10;b=20;}
 ~B() {Release(); cout<<a<<b<<endl;}
 void Release() { cout<<"Releasing B"; b = 0; }
};

int main()
{
    {
      B b;
      b.Release();
      b.b=100;  // why this step is executed?
    }
    int x;
    cin>>x;
    return 0;
}

否则当超出范围时 B 将被删除:

int main()
{
    {
      B b;
      b.b = 100;  //OK
    }
    b.b = 100; //compile time error
    int x;
    cin>>x;
    return 0;
}

Destructors were not designed to call them explicitly. Basically it is just another (special) method of class.
If you want to Uninitialize your object and then still be able to use it you could make our own method:

class B: public A
{
public:
 int b;
 B() {cout<<"b"<<endl;a=10;b=20;}
 ~B() {Release(); cout<<a<<b<<endl;}
 void Release() { cout<<"Releasing B"; b = 0; }
};

int main()
{
    {
      B b;
      b.Release();
      b.b=100;  // why this step is executed?
    }
    int x;
    cin>>x;
    return 0;
}

Otherwise B will be deleted when out of scope:

int main()
{
    {
      B b;
      b.b = 100;  //OK
    }
    b.b = 100; //compile time error
    int x;
    cin>>x;
    return 0;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文