构造函数/析构函数计数不匹配[重复]
Posted
技术标签:
【中文标题】构造函数/析构函数计数不匹配[重复]【英文标题】:mismatch in constructors/destructors count [duplicate] 【发布时间】:2011-09-30 08:28:44 【问题描述】:可能重复:C++ basic constructors/vectors problem (1 constructor, 2 destructors)
我有代码:
#include <iostream>
class A
public:
A() std::cout<<"A::A"<<std::endl;
~A() std::cout<<"A::~A"<<std::endl;
;
class B : public A
public:
B() std::cout<<"B::B"<<std::endl;
~B() std::cout<<"B::B"<<std::endl;
;
void Func( A a )
int main()
B b;
Func(b);
在 VS2010EE 中输出将是:
A::A
B::B
A::~A //why twice? Once on gcc!
A::~A
B::~B
A::~A
但是,当我们有复制构造函数时,输出是:
A::A
B::B
A::A(copy)
A::~A
B::~B
A::~A
【问题讨论】:
你总是有一个副本 cosnstructor。如果你自己没有声明一个,而是隐式使用它,编译器会为你定义一个,而提供的编译器不会记录到std::cout
。
~B
应该打印"B::~B"
,而不是"B::B"
。
如果你在 A 析构函数中设置了一个断点,你应该看到它是从哪里被调用的。
@CharlesBailey:谢谢,这经常弹出,但我找不到重复的:/
@CharlesBailey :不确定是不是骗子:为什么 A 析构函数被调用 3 次?我可以理解两个(一个用于临时 A 参数,一个用于原始对象......)
【参考方案1】:
这有点不幸。 VS 应该避免第二个副本;所有优化都在吗?据推测,它在b
的A
部分调用复制构造函数来创建参数(即对其进行切片),然后将该对象再次复制到堆栈中以进行函数调用。 (在第一个示例中,A
的构造函数没有被调用,因为生成的复制构造函数不打印输出。)当您提供复制构造函数时,它必须直接在堆栈上创建副本。
【讨论】:
那个副本现在不能省略了,可以吗? 我已经尝试了几个优化设置 - 没有变化! '然后将该对象复制到堆栈上':那么它会将第一个复制构造的对象放在哪里? (好点 Roddy;我的意思是函数框架而不是作用域的堆栈框架。)@Martino:如果 gcc 正在执行它,则两个副本之一可以,除非它正在执行不符合标准的操作。您可能希望生成一个直接复制到堆栈的构造函数;可能 VS 正确语义的想法有一些理由不允许这样做,但我不能立即想到它可能是什么。 我不认为有任何利润,但也没有任何东西会禁止它。在任何一种情况下,复制一份或两份都是完全合法的。我怀疑 MSVC 会特例处理琐碎的复制构造函数,并以某种方式错过了合并这两个操作的可能性。【参考方案2】:你没有计算所有的构造函数。在第一种情况下,调用Func
时会调用复制构造函数来创建对象的副本(因为该函数通过值获取其参数)。
当您自己不定义复制构造函数时,编译器会为您生成一个。并且编译器生成的复制构造函数不会打印任何内容,因此它不会出现在您的输出中。
【讨论】:
问题是为什么在使用编译器生成的 copy-ctor 时会出现第二个副本。一份就够了。 因为您创建了两个副本。首先,您在main
中创建一个实例,然后将该实例传递给Func
,因为它按值获取参数,所以创建了它的副本。该副本可以被编译器优化掉,但是当您天真地阅读代码时,您会告诉它创建类的实例,然后创建该实例的副本。
“因为你创建了两个副本。首先你在 main 中创建了一个实例”——输出的最后几行对应于 main 中的对象。【参考方案3】:
如果我理解正确,您实际上是在问这个:
VS2010为什么在我没有副本的时候创建一个additional临时 构造函数?
我唯一的答案是“因为它被允许”。似乎在您使用 gcc 时它会被优化掉,并且在您提供用户定义的复制构造函数时也会被优化掉。
这种行为有点奇怪,但完全符合要求。如果所有 C++ 编译器的性能相同,我们只需要一个编译器...
【讨论】:
以上是关于构造函数/析构函数计数不匹配[重复]的主要内容,如果未能解决你的问题,请参考以下文章