V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Distributions
Ubuntu
Fedora
CentOS
中文资源站
网易开源镜像站
James369
V2EX  ›  Linux

C++的缺省拷贝构造和浅拷贝有没有区别?

  •  
  •   James369 · 2021-02-05 09:15:05 +08:00 · 2637 次点击
    这是一个创建于 1392 天前的主题,其中的信息可能已经有所发展或是发生改变。

    比如一个类:

    class Test {
    public:
        std::string s;    //s 在浅拷贝的时候,是否会调用 std::string 的拷贝构造?
        float a;
    }
    
    std::shared_ptr<Test> function() {
        ...
        auto test = Test();  //栈上创建
        test.s = "aaa";    
        test.a = 111;
        auto result = std::make_shared<Test>(test);  //调用 Test 缺省构造函数,即 memcpy?
        return result;
    }
    
    int main() {
        auto ret = function();
        ...
    }
    
    

    此时发生浅拷贝,如果直接 memcpy 覆盖过去,那么成员变量 s 指向的字符串的内容是栈上的,离开栈就会发生内存访问错误。但实际测试并没有发生内存错误。

    第 1 条附言  ·  2021-02-05 15:05:27 +08:00
    经测试,会调用 std::string 的拷贝构造函数,也就是说浅拷贝不仅仅是内存的二进制简单复制。
    同时,将 class Test 改为结构体 struct Test,也是一样的结果。
    15 条回复    2021-02-05 11:44:58 +08:00
    norz
        1
    norz  
       2021-02-05 09:24:29 +08:00   ❤️ 1
    string 的拷贝构造会执行
    auto8888
        2
    auto8888  
       2021-02-05 09:27:10 +08:00
    string 不是指针成员呢,亲亲。
    norz
        3
    norz  
       2021-02-05 09:28:42 +08:00
    浅拷贝并不是 memcpy,而是直接赋值
    owwlo
        4
    owwlo  
       2021-02-05 09:28:56 +08:00   ❤️ 1
    像楼上说的,默认是拷贝构造函数并不会是 memcpy,即使是编译器优化,我“猜”编译器也只会对 std:: is_trivially_copyable 的结构执行 memcpy 。
    James369
        5
    James369  
    OP
       2021-02-05 09:29:18 +08:00
    @norz 如果是这样,那么浅拷贝就不是简单的 memcpy 的二进制复制了?
    freemon
        6
    freemon  
       2021-02-05 09:32:05 +08:00
    stl::string 抽象出来的代码不是这样吗
    freemon
        7
    freemon  
       2021-02-05 09:32:14 +08:00
    class string {
    enum { _BUF_SIZE = 16 };
    union _Bxty {
    // storage for small buffer or pointer to larger one
    char _Buf[_BUF_SIZE];
    char* _Ptr;
    } _Bx;
    size_t _Mysize; // current length of string
    size_t _Myres; // current storage reserved for string
    };
    levelworm
        8
    levelworm  
       2021-02-05 09:54:44 +08:00 via Android
    浅拷贝就是一个个 bit 复制过去吧?类里带指针需要在堆上创建对象的必须用深拷贝。
    auto8888
        9
    auto8888  
       2021-02-05 09:59:57 +08:00
    "aaa" 存储在文字常量区
    hitmanx
        10
    hitmanx  
       2021-02-05 10:28:11 +08:00   ❤️ 1
    string 不是 const char*,它是把字符串存在 heap 里的。且哪怕是 const char*,这个指针指向也是没问题的。就像楼上说的,"aaa"是在常量区的,而不是注释里写的在栈上
    amaranthf
        11
    amaranthf  
       2021-02-05 10:33:49 +08:00
    浅拷贝,指的是一种“变量间赋值的方式”,而“class 的默认复制构造并非浅拷贝”。
    class 的默认复制构造函数中,只有对指针成员才会进行浅拷贝,即直接赋值,对对象类型的成员会执行其默认复制构造。
    alazysun
        12
    alazysun  
       2021-02-05 10:41:03 +08:00
    缺省的拷贝构造就是浅拷贝,但对有拷贝构造函数的成员,则会调用它的拷贝构造。
    lvzx
        13
    lvzx  
       2021-02-05 11:12:26 +08:00 via Android
    你自己写个类,拷贝构造加点打印不就知道了?自动生成的拷贝构造函数,会调用成员变量的拷贝构造函数,所以 string 当然不会有问题
    xuanbg
        14
    xuanbg  
       2021-02-05 11:14:03 +08:00
    浅拷贝只是复制指针,深拷贝是复制数据+新的指针。
    walker522
        15
    walker522  
       2021-02-05 11:44:58 +08:00
    深浅拷贝是相对于能否级联复制指针所指内容的,是类型的拷贝函数设计问题。
    而正确设计的对象和基本类型是可以自动级联复制。
    make_shared 先在堆上分配内存,再执行对象拷贝。
    string 拷贝内部会进行了指针内容拷贝,是深拷贝。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1434 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 23:51 · PVG 07:51 · LAX 15:51 · JFK 18:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.