Visual C++:按值复制到函数参数在 VS2012 中生成两个对象
visual c++: copy by value to function params produce two objects in vs2012
这是在 g++ 4.7 和 vs2012 (cl17) 中生成不同输出的代码。
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "1" << endl; }
~A() { cout << "2" << endl; }
};
class B : public A
{
public:
B() { cout << "3" << endl; }
~B() { cout << "4" << endl; }
};
void func(A a) {}
int main()
{
B b;
func(b);
return 0;
}
GCC 输出13242
,而 cl 输出132242
。
为什么 cl 编译器在堆栈上创建副本时会生成第二个 A
对象,目的是什么?
这似乎是一个编译器错误。
C++标准不使用术语对象切片,您正在将类型B
的对象传递给接收类型为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)
你遇到了编译器的错误。
正确的功能解释如下:
该函数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() 调用是在复制构造的对象 A 在func
调用结束时被销毁时进行的。
相关文章:
- 如何返回一个类的两个对象相加的结果
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 停止cmake target_link_libraries将插件中静态库的两个对象文件链接到静态库本身
- 为什么C++在将一个对象复制到另一个对象时需要对这两个对象进行低级常量限定
- 我有两个类需要在同一 cpp 文件中相互引用,但第一个类无法识别第二个类类型的对象
- int数据类型的指针指向的是什么,如果是一个类的私有数据成员,我们创建了该类的两个对象?
- 如何从文件中读取两个字符串和数字数组,并将它们存储在对象向量中
- 在什么情况下,两个堆栈分配的结构对象的 this 点指向同一个地址?
- 通过插槽和信号在不同线程中的两个qt对象之间进行通信
- 具有相同特征的两个对象是否只在内存中存储一次?无论定义它们的函数是什么,都是不同的
- 如何在Qt中连接来自不同窗口的两个对象?
- 是否可以使用非常量指针调用非常量函数,以及当两个unique_ptrs指向同一个对象时程序的行为方式?
- C++两个对象,其中包含指向同一数组不同部分的指针
- 为什么将两个对象分配给另一个对象后,两个对象不一样?
- 绘制一个对象,比较模具缓冲区的两个不同值
- C++控制台应用,其中有两个冲突的对象不工作
- C++ 如何将两个 makefile 对象目标规则(位于另一个文件夹中)合并到一个目标/规则中?
- 当两个 std::map 对象相同时
- C++:在另外两个对象之间共享一个对象
- 为什么这两个卡片对象不等同?