zoukankan      html  css  js  c++  java
  • C++编译器什么时候为我们自动生成拷贝构造函数?

    StackOverflow上有个一个有趣的问题,copy by value to function params produce two objects in vs2012

    给出程序:

    #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;
    }

    Visual Studio给出的输出是:132242。

    前两个13和最后两个42.是对应的,分别是main函数中的局部变量b的构造和析构。问题出在中间的两个2,说明在调用函数func的时候创建了两个临时的A。

    看到这个程序,第一眼的感觉应该是:因为func是参数是值传递,所以b传给func时,调用了A的拷贝构造函数,从b生成了一个A的临时变量,推出func时,这个临时变量析构,所以应该只有一个2.

    但是为什么会有两次呢?打开disassembly window,我们可以看到如下的汇编代码:

    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的析构函数改成virtual,这样,输出的结果就是13242,中间只有1个2,说明只有一个临时的A被创建了出来,是我们期望的结果。汇编代码如下:

    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)

    回想Inside C++ object model中说到的只有在4中情况下编译器才会给我们生成缺省拷贝构造函数:

    1. 类包含的成员变量是object,并且这个object的类有拷贝构造函数。
    2. 类继承自一个基类,这个基类有拷贝构造函数。
    3. 类声明了1个或者多个虚函数。
    4. 类继承自一个基类,这个基类有1个或者多个虚函数。

    所以在原来的代码中A不属于上面4类,所以编译器不会为它生成一个缺省拷贝构造函数。

    我把我的理解写在了这个答案里。

  • 相关阅读:
    Spring基础知识点总结
    秒懂设计模式--代理模式(proxy)
    秒懂设计模式--工厂模式
    秒懂设计模式--适配器模式
    秒懂设计模式--装饰者模式
    秒懂设计模式--观察者模式
    单例模式的几种实现
    springboot2.0+spring cloud+eureka搭建微服务步骤
    字符串排序算法
    bitbucket的简单使用
  • 原文地址:https://www.cnblogs.com/fresky/p/2787960.html
Copyright © 2011-2022 走看看