C++ c++;:按值复制到函数参数在vs2012中生成两个对象
下面是在g++4.7和vs2012(cl17)中生成不同输出的代码C++ c++;:按值复制到函数参数在vs2012中生成两个对象,c++,visual-c++,gcc,visual-studio-2012,gcc4.7,C++,Visual C++,Gcc,Visual Studio 2012,Gcc4.7,下面是在g++4.7和vs2012(cl17)中生成不同输出的代码 #包括 使用名称空间std; 甲级 { 公众: A(){cout您遇到了编译器的错误 正确的功能说明如下: 函数func需要创建对象的副本(但要注意切片) 那么,发生的情况是: int main() { // create object B, which first creates the base object A B b; // create object A, using this copy co
#包括
使用名称空间std;
甲级
{
公众:
A(){cout您遇到了编译器的错误
正确的功能说明如下:
函数func
需要创建对象的副本(但要注意切片)
那么,发生的情况是:
int main()
{
// create object B, which first creates the base object A
B b;
// create object A, using this copy constructor : A( const B& )
func(b);
}
额外的~A()调用是在func
调用结束时复制构造的对象A被销毁时进行的。这似乎是一个编译器错误。
C++标准不使用强>对象切片< /St>,将一个对象的代码<代码> b/COD>传递到一个函数,接收一个类型<代码> A/<代码>的参数。编译器将应用通常的过载分辨率来找到合适的匹配。
基类A
具有编译器提供的复制构造函数,该构造函数将引用A
,在没有其他转换函数的情况下,这是最佳匹配,编译器应该使用它
请注意,如果有更好的转换可用,则将使用它。例如:如果A
有一个构造函数A::A(B const&)
,除了复制构造函数之外,还将使用此构造函数,而不是复制构造函数。C++编译器将在以下情况下合成默认的复制构造函数。(从C++对象模型内部)
当类包含存在副本构造函数的类的成员对象时
当该类派生自存在副本构造函数的基类时
当类声明一个或多个虚拟函数时
从继承链派生类时,其中一个或多个基类是虚拟的
我们可以看到类A不在这4种情况下。所以cl不为它合成默认的复制构造函数。也许这就是为什么2个临时A对象被构造和销毁的原因
从disassemly窗口中,我们可以看到以下代码,没有调用A::A.:
B b;
00B317F8 lea ecx,[b]
00B317FB call B::B (0B31650h)
00B31800 mov dword ptr [ebp-4],0
func(b);
00B31807 mov al,byte ptr [ebp-12h]
00B3180A mov byte ptr [ebp-13h],al
00B3180D mov byte ptr [ebp-4],1
00B31811 movzx ecx,byte ptr [ebp-13h]
00B31815 push ecx
00B31816 call func (0B31730h)
但是如果我们将析构函数设为虚拟的,我们将得到下面的反汇编代码,我们可以看到调用了A::A。然后结果正如预期的那样,只创建了1个对象
B b;
00331898 lea ecx,[b]
0033189B call B::B (03316A0h)
003318A0 mov dword ptr [ebp-4],0
func(b);
003318A7 push ecx
003318A8 mov ecx,esp
003318AA mov dword ptr [ebp-1Ch],esp
003318AD lea eax,[b]
003318B0 push eax
003318B1 call A::A (0331900h)
003318B6 mov dword ptr [ebp-20h],eax
003318B9 call func (03317D0h)
在VS2010上进行了测试,结果是“132242”,而发布版本仅生成13242,但在添加(常量A&A)时不生成调试版本{cout@ElektroKraut:不。只是不。只在必要时使用虚拟
。另一方面,如果不是虚拟
,则受保护
可能是个好主意;如果使用-Wdelete非虚拟数据或
编译,编译器将为您标记所有不正确的使用。在Visual Studio 6上测试,结果相同,这是一个好主意这是一个很长的bug,自1998年(VS 6发布时)以来已有12年多了。在“cl输出”中,在func()
的末尾有两次调用~a
。这似乎是个问题。@KevinBallard我解释了应该发生什么。我将这种行为称为编译器的bug。有些人会称之为扩展;)@应该发生什么已经是个问题了;这只是一个重述。a
的显式琐碎复制构造函数修复了VS2010中的问题,这对我来说没有多大意义。@Gorpik:有更多的理由相信这是一个编译器错误。重载解析规则很复杂,但这种情况似乎是o更常见的错误之一。编译器错误是否有意义?强制编译器生成稍有不同的符号表示可以很容易地隐藏错误。@Gorpik VS2008Downvoter中的相同行为:与不合理的downvoting不同,请添加一个解释,说明为什么您认为此答案是错误的,最好是引用标准中的引用我们在这里帮助事业。
B b;
00331898 lea ecx,[b]
0033189B call B::B (03316A0h)
003318A0 mov dword ptr [ebp-4],0
func(b);
003318A7 push ecx
003318A8 mov ecx,esp
003318AA mov dword ptr [ebp-1Ch],esp
003318AD lea eax,[b]
003318B0 push eax
003318B1 call A::A (0331900h)
003318B6 mov dword ptr [ebp-20h],eax
003318B9 call func (03317D0h)