为什么我们说对象超出范围时析构函数调用?

时间:2015-06-07 16:03:47

标签: c++ destructor

我了解到当对象超出范围并且析构函数删除对象时会调用析构函数。好的,但是这里发生了什么?

我明确地调用了析构函数,如果它删除了对象,那么为什么隐式调用析构函数呢?即使现在没有对象,因为它已经被明确的析构函数调用删除了。对不起,我可能是明确而含蓄的错误但是试着理解我的问题。

#include <iostream>
using namespace std;
class A{
    public:
        A(){
            cout << "Constructor" << endl;
        }
        ~A(){
            cout << "Destructor" << endl;
        }

};
int main(){
    A obj;
    obj.~A();
    cout << "End" << endl;
}

现在

obj.~A();

上面的行删除了该对象。然后为什么再次调用析构函数?即使没有任何对象。

输出:

Constructor
Destructor
End
Destructor

4 个答案:

答案 0 :(得分:4)

超出范围的对象的析构函数被调用。这是C ++语言标准强制要求的不可改变的保证。如果您事先手动调用析构函数并不重要;当它超出范围时,将调用析构函数。如果你已经编写了析构函数,如果它被调用两次就会发生坏事,或者如果编译器插入析构函数代码中的额外行为不想被调用两次,那么坏事就会发生发生。

这是您不应该手动调用析构函数的众多原因之一。

答案 1 :(得分:1)

析构函数删除对象,它会破坏它。 除非对象是POD类型(基本上,你的东西 可以在C)中定义,破坏已被破坏的对象 未定义的行为。由于所有变量都会自动拥有 他们应该在他们的生命结束时召唤他们的析构者 从不在它们上显式调用析构函数。同样,如果你 使用非展示形式的new创建了对象: 显式调用析构函数不会释放内存;您 应该使用delete,它调用析构函数然后释放 记忆。

你应该明确调用析构函数的时间是 你已经使用了placement new来构造对象,以便 单独分配和初始化。今天,这样的技术 应该被认为是先进的,而且很少见 程序员需要它们。

答案 2 :(得分:1)

您提供的课程没有管理任何数据,因此其析构函数没有任何可以释放的对象。这就是为什么你能够两次调用析构函数而没有任何后果的原因。这是一个未通过相同测试的示例类:

#include <iostream>


class A {
 public:
  A() {
    std::cout << "constructing..." << '\n';
    val = new int;
  }

  ~A() {
    std::cout << "destructing..." << '\n';
    delete val;
  }

 private:
  int* val;
};


int main() {
  A obj;
  obj.~A();
  std::cout << "End" << '\n';
  return 0;
}

构造函数在堆上为val分配空间,析构函数运行delete以释放该空间。在~A()中调用main()两次(首先是显式的,然后是隐式的),这可以理解地导致内存错误。

查看此链接以获取有关析构函数如何工作的更多信息: https://isocpp.org/wiki/faq/dtors

答案 3 :(得分:0)

您的对象不包含任何指针。它在调用时不释放析构函数中的任何对象,因此在多次调用时不会造成任何损害。 如果析构函数删除指针并且那些指针未设置为0(这在析构函数中通常是这种情况),那么析构函数的第二次调用将是有害的,因为它会导致内存错误。