C ++中的对象破坏

时间:2011-06-19 14:43:20

标签: c++ exception destructor c++-faq object-lifetime

当C ++中的对象被破坏时,这是什么意思?我是否必须手动销毁它们,因为没有垃圾收集器?例外如何发挥作用?

<子> (注意:这是Stack Overflow's C++ FAQ的一个条目。如果您想批评在此表单中提供常见问题解答的想法,那么the posting on meta that started all this就是这样做的地方。在C++ chatroom中监控了这个问题,首先是FAQ的想法,所以你的答案很可能会被那些提出想法的人阅读。)

2 个答案:

答案 0 :(得分:78)

答案 1 :(得分:35)

当对象生命周期结束并被销毁时,会自动调用对象的析构函数。你通常不应该手动调用它。

我们将使用此对象作为示例:

class Test
{
    public:
        Test()                           { std::cout << "Created    " << this << "\n";}
        ~Test()                          { std::cout << "Destroyed  " << this << "\n";}
        Test(Test const& rhs)            { std::cout << "Copied     " << this << "\n";}
        Test& operator=(Test const& rhs) { std::cout << "Assigned   " << this << "\n";}
};

C ++中有三种(C ++ 11中有四种)不同类型的对象,对象的类型定义了对象的生命周期。

  • 静态存储持续时间对象
  • 自动存储持续时间对象
  • 动态存储持续时间对象
  • (在C ++ 11中)线程存储持续时间对象

静态存储持续时间对象

这些是最简单的,等同于全局变量。这些对象的生命周期(通常)是应用程序的长度。这些(通常)是在我们退出main之后(在创建的主顺序中)之前构建的。

Test  global;
int main()
{
    std::cout << "Main\n";
}

> ./a.out
Created    0x10fbb80b0
Main
Destroyed  0x10fbb80b0

注1:还有另外两种静态存储持续时间对象。

类的静态成员变量。

就生命周期而言,这些意义和目的与全局变量相同。

函数内的静态变量。

这些是懒惰创建的静态存储持续时间对象。它们是在第一次使用时创建的(在C ++ 11的线程安全庄园中)。与其他静态存储持续时间对象一样,它们在应用程序结束时被销毁。

施工/销毁顺序

  • 编译单元内的构造顺序定义明确,与声明相同。
  • 编译单元之间的构造顺序未定义。
  • 破坏的顺序与构造顺序完全相反。

自动存储持续时间对象

这些是最常见的对象类型,99%的情况下你应该使用它们。

这是三种主要类型的自动变量:

  • 函数/块内的局部变量
  • 类/数组中的成员变量。
  • 临时变量。

本地变量

当退出一个函数/块时,在该函数/块内声明的所有变量都将被销毁(按照创建的相反顺序)。

int main()
{
     std::cout << "Main() START\n";
     Test   scope1;
     Test   scope2;
     std::cout << "Main Variables Created\n";


     {
           std::cout << "\nblock 1 Entered\n";
           Test blockScope;
           std::cout << "block 1 about to leave\n";
     } // blockScope is destrpyed here

     {
           std::cout << "\nblock 2 Entered\n";
           Test blockScope;
           std::cout << "block 2 about to leave\n";
     } // blockScope is destrpyed here

     std::cout << "\nMain() END\n";
}// All variables from main destroyed here.

> ./a.out
Main() START
Created    0x7fff6488d938
Created    0x7fff6488d930
Main Variables Created

block 1 Entered
Created    0x7fff6488d928
block 1 about to leave
Destroyed  0x7fff6488d928

block 2 Entered
Created    0x7fff6488d918
block 2 about to leave
Destroyed  0x7fff6488d918

Main() END
Destroyed  0x7fff6488d930
Destroyed  0x7fff6488d938

成员变量

成员变量的生命周期绑定到拥有它的对象。当业主的寿命结束时,其所有成员的寿命也将结束。因此,您需要查看遵守相同规则的所有者的生命周期。

注意:成员总是在所有者之前按照相反的创建顺序销毁。

  • 因此,对于班级成员,他们是按照声明的顺序创建的 并按照与声明相反的顺序销毁
  • 因此,对于数组成员,它们按顺序0 - >顶部
    创建 并以相反的顺序销毁 - > 0

临时变量

这些是作为表达式结果创建但未分配给变量的对象。临时变量就像其他自动变量一样被销毁。只是它们范围的结尾是创建它们的语句的结尾(这通常是';')。

std::string   data("Text.");

std::cout << (data + 1); // Here we create a temporary object.
                         // Which is a std::string with '1' added to "Text."
                         // This object is streamed to the output
                         // Once the statement has finished it is destroyed.
                         // So the temporary no longer exists after the ';'

注意:有些情况下可以延长临时寿命 但这与这个简单的讨论无关。当你明白这个文件对你来说是第二天性的时候,在它延长之前,暂时的生命不是你想做的事情。

动态存储持续时间对象

这些对象具有动态生命周期,使用new创建,并通过调用delete销毁。

int main()
{
    std::cout << "Main()\n";
    Test*  ptr = new Test();
    delete ptr;
    std::cout << "Main Done\n";
}

> ./a.out
Main()
Created    0x1083008e0
Destroyed  0x1083008e0
Main Done

对于来自垃圾收集语言的开发人员来说,这看起来很奇怪(管理对象的生命周期)。但问题并不像看起来那么糟糕。在C ++中直接使用动态分配的对象是不常见的。我们有管理对象来控制他们的生命周期。

与大多数其他GC收集的语言最接近的是std::shared_ptr。这将跟踪动态创建的对象的用户数量,当所有这些对象都消失后,将自动调用delete(我认为这是普通Java对象的更好版本)。

int main()
{
    std::cout << "Main Start\n";
    std::shared_ptr<Test>  smartPtr(new Test());
    std::cout << "Main End\n";
} // smartPtr goes out of scope here.
  // As there are no other copies it will automatically call delete on the object
  // it is holding.

> ./a.out
Main Start
Created    0x1083008e0
Main Ended
Destroyed  0x1083008e0

线程存储持续时间对象

这些是该语言的新功能。它们非常类似于静态存储持续时间对象。但是,与他们所居住的应用程序生活相同的生命,只要它们与执行的线程相关联。