【问题标题】:Why is there more destructor calls than constructor calls为什么析构函数调用比构造函数调用多
【发布时间】:2021-04-01 11:07:47
【问题描述】:

我正在测试以下代码,令我困惑的是析构函数调用比构造函数调用多:

#include <iostream>

struct A {
    A() { std::cout << 1; }
    A(int) { std::cout << 7; }
    ~A() { std::cout << 5; }
};

struct B {
    B() { std::cout << 2; }
    B(int) { std::cout << 9; }
    ~B() {std::cout << 3;}
};

struct C {
    B b;
    A a1;
    A a2;
    C() : a1(3){
        b = 3;
        a2 = 7;
    }
};

int main(){
    C c;
    return 0;
}

输出如下:

B()  A(int) A() B(int) ~B() A(int) ~A() ~A() ~A() ~B() 
 2     7     1    9      3     7     5    5    5    3

我的猜测是,在 b = 3 和 a2 = 7 行中,3 和 7 必须隐式转换为 B 和 A,当它们被复制到 b 和 a2 时,它们会被销毁。

这是正确的还是这里发生了其他事情?

【问题讨论】:

  • 在您提供的输出中,我看到对构造函数和析构函数的调用次数相同:3 对 A 和 2 的调用对呼叫对B。我错过了什么?
  • 出于某种原因,我认为 A(int) 构造函数是复制构造函数,而不是基本构造函数。我现在想通了..
  • 如果你输出this 的值而不是那些数字,你会得到更好的结果。您会很快看到一些被销毁的对象没有被您的代码正确跟踪。
  • 现在我已经阅读了所有这些答案,我觉得问这个问题有点愚蠢,因为我现在很清楚这里发生了什么。我出于某种原因认为 A(int) 正在将整数值复制到 b/a2 中,它实际上是在构造一个临时对象,然后将副本分配到 b/a2 中。感谢您的帮助!

标签: c++ constructor destructor


【解决方案1】:

您没有记录复制构造函数和复制赋值运算符,例如:

struct A {
    A() { ... }
    A(int) { ... }
    A(const A&) { ... } // <-- add this
    ~A() { ... }
    A& operator=(const A&) { ...; return *this; } // <-- add this
};

struct B {
    B() { ... }
    B(int) { ... }
    B(const B&) { ... } // <-- add this
    ~B() { ... }
    B& operator=(const B&) { ...; return *this; } // <-- add this
};

但是,如果您实际计算所显示的输出,您会发现您正在看到匹配的构造函数和析构函数。您有 3 个 A 构造函数调用和 3 个 ~A 析构函数调用。你有 2 个 B 构造函数调用和 2 个 ~B 析构函数调用。

B()         C::b
A(int)      C::a1
A()         C::a2
B(int)      temp
B=          temp -> C::b
~B()        temp
A(int)      temp
A=          temp -> C::a2
~A()        temp
~A()        C::a2
~A()        C::a1
~B()        C::b

Demo

【讨论】:

  • coliru.stacked-crooked.com/a/64da8fe376f01e45 问题在于复制分配,而不是复制构造函数
  • 旁注:我真的认为用户定义的析构函数会删除默认生成的复制构造函数和赋值。我很震惊,事实并非如此。
  • @MooingDuck - 为什么会这样?
  • @Dzamba 您正在看到临时对象被破坏。计算输出。您有 3 个 A 正在构造和销毁的对象,还有 2 个 B 正在构造和销毁的对象。
  • @StoryTeller-UnslanderMonica:我假设是因为自定义析构函数几乎总是意味着 RAII,这意味着非平凡的副本。相反,它只检查复制/移动ctors+assignment。 stackoverflow.com/questions/4943958/…
猜你喜欢
  • 1970-01-01
  • 2011-04-16
  • 2020-08-24
  • 2015-04-28
  • 1970-01-01
  • 2021-12-26
  • 1970-01-01
  • 2021-07-19
  • 2017-02-08
相关资源
最近更新 更多