【问题标题】:How the constructor and destructor work?构造函数和析构函数如何工作?
【发布时间】:2017-05-20 03:22:08
【问题描述】:
class Foo{
public:
    Foo(){
        cout <<"C ";
    }
    ~Foo(){
        cout <<"D ";
    }
};

void func(){
    Foo* p = new Foo;
    p = NULL;
}

int main(){
    Foo a;
    for (int i=0; i<1; i++){
        Foo b;
        if (true){
            Foo c;
        }
        func();
    }
    return 0;
}

对于这个问题,输出是C C C D C D D,如果我删除main函数中的func(),输出就变成了C C C D D D,我明白它来自哪里的前3个C,但是我不明白剩下的,请解释一下,谢谢。

【问题讨论】:

  • for (int i=0; i&lt;1; i++) 基本上只执行一次它的块,if(true) 也是如此。如果要定义范围,只需使用一对大括号 ({ })。你不需要在流控制语句的上下文中使用它们,你可以简单地做int main(){ Foo a; { Foo b; { Foo c; } func(); } return 0; }
  • 使用调试器逐步完成可能会有所帮助...
  • p = NULL; 实际上并没有销毁对象。 new Foo 对象被泄露。此行应为delete p;
  • 您似乎对析构函数的作用以及对象生命周期的工作方式感到困惑。这对于 c++ 来说是非常基础的东西,最好由 good book 覆盖。
  • 如果您要添加一些调试消息,您会注意到按退出范围的顺序,ctor 用于 abcp,dtor 用于 cba。 P 泄漏。

标签: c++ constructor destructor


【解决方案1】:

对象a的范围是函数main的外部代码块的范围。它是创建的第一个对象,也是删除的最后一个对象。

int main(){
    Foo a;
    // ...
    return 0;
}

C C C D C D D
|           |
a           a

然后在只有一次迭代的 for 循环中创建对象b,该对象在循环的第一次迭代后被删除

for (int i=0; i<1; i++){
    Foo b;
    // ...
}

C C C D C D D
| |       | |
a b       b a

然后在if语句的块范围内

    if (true){
        Foo c;
    }

有创建和删除对象c

C C C D C D D
| | | |   | |
a b c c   b a

之后调用函数func

func();

在函数内部,使用运算符 new 创建了一个未命名的对象,并由指针 p 指向。

void func(){
    Foo* p = new Foo;
    p = NULL;
}

C C C D C D D
| | | | | | |
a b c c p b a

这个对象没有被删除,因为没有为此对象调用操作符delete。所以存在内存泄漏。

就是这样。

【讨论】:

    【解决方案2】:
    1. C - a 被构造
    2. C - b 被构造
    3. C - c 被构造
    4. D - c 被破坏,因为你离开了作用域
    5. C - 对象 Foo 是动态分配并由 p 指向的,但由于它是动态分配的,并且从未被删除,因此它永远不会被破坏。
    6. D - b 被破坏
    7. D - a 被破坏

    【讨论】:

      【解决方案3】:

      顺序是 C C C D C D D:

      1. C - 构造 A
      2. C - 构造 B
      3. C - 构造 C
      4. D - 破坏 C
      5. C - 构造 p(在 func 中)
      6. D - 破坏 B
      7. D - 破坏 A

      // memleak for p (in func)

      【讨论】:

        【解决方案4】:

        当包含func(); 调用时,采取的步骤是:

        Foo a; -> C
        
        Foo b; -> C
        
        Foo c; -> C
        
        Left the scope of Foo c -> D
        
        func(); call ->
            new Foo; -> C
        
        Finished func() call, left the scope of Foo b -> D
        
        Left the scope of Foo a -> D
        

        请注意,在 func() 中创建的 Foo 对象永远不会被解构,这意味着您有内存泄漏。

        【讨论】:

          猜你喜欢
          • 2011-01-26
          • 2013-07-07
          • 2018-09-23
          • 2021-07-28
          • 2011-04-03
          • 2010-12-16
          • 2016-11-04
          • 2011-12-27
          • 1970-01-01
          相关资源
          最近更新 更多