请教下关于拷贝构造函数的问题 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
frankmdong
V2EX    C++

请教下关于拷贝构造函数的问题

  •  
  •   frankmdong 2022-07-20 00:53:22 +08:00 2146 次点击
    这是一个创建于 1245 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近在看 Professional C++, Fifth Edition 入门,看到 rule of five 和移动构造函数的时候写了个示例测了下,发现一个奇怪的问题。

    为什么 std::vector<Data> myDatas{data}; 这行会调两次 Data 的拷贝构造函数呢?是复制初始化导致的吗?

    如果我改成 std::vector<Data> myDatas; 然后 push_back(data), 这里就只会打印一次 "Copy constructor"。

    另外:C++ 一般这种问题应该怎么分析?一般是看汇编还是断点?

    int main() { DataHolder wrapper; Data data{11}; // Normal constructor std::vector<Data> myDatas{data};// Copy constructor * 2 wrapper.setDatas(myDatas); // Copy constructor } 

    全代码在:https://godbolt.org/z/EE5vnG3Kz

    菜鸟问题有点多,不好意思

    8 条回复    2022-07-21 00:44:29 +08:00
    pocarisweat
        1
    pocarisweat  
       2022-07-20 01:16:22 +08:00   1
    https://stackoverflow.com/questions/20501638/stdvector-init-with-braces-call-copy-constructor-twice

    因为 std::vector { data } 实际上调用的是 std::initializer_list 版本的构造函数,所以从 data 到 initializer_list copy 了一次,而从 initializer_list 到 vector 又 copy 了一次。如果写成 std::vector { std::move(data) } 会发现 move 了一次 copy 了一次。

    如果你写成 std::vector(1, data) 就会只 copy 一次。
    pocarisweat
        2
    pocarisweat  
       2022-07-20 01:19:42 +08:00
    @pocarisweat
    不过这里是因为 Data 的复制构造函数有副作用,所以按照语言标准必须调用两次。如果没有副作用,编译器后端很容易(但不保证)将其优化掉。这有点类似物理学的不确定性原理
    frankmdong
        3
    frankmdong  
    OP
       2022-07-20 11:07:13 +08:00
    @pocarisweat #2 #2 感谢回复!
    “Data 的复制构造函数有副作用” 中的副作用是指我自定义了复制构造函数吗?
    在 godbolt 里面还有一处是

    DataHolder wrapper;
    std::vector<Data> myDatas{11}; // 11 是隐式构造 Data{11}
    wrapper.setDatas(myDatas);

    这样写的话,std::initializer_list 那里又变成只有一次 Copy constructor 了,感觉就是...很迷...
    cnbatch
        4
    cnbatch  
       2022-07-20 14:10:35 +08:00   1
    也许这样描述会清楚一点


    std::vector<Data> myDatas { data }

    第一次 Copy constructor:data“塞入”std::initializer_list{}
    第二次 Copy constructor:从 std::initializer_list{} “变成” std::vector<Data>



    std::vector<Data> myDatas{11}

    第一次 Copy constructor:11“塞入”std::initializer_list{}。数字 11 此时不是 class Data ,仅仅是简单的基本类型复制,跟那个 class 暂时还没关联,并不会用到你在 class Data 提供的 Copy constructor 。
    第二次 Copy constructor:从 std::initializer_list{} “变成” std::vector<Data>
    frankmdong
        5
    frankmdong  
    OP
       2022-07-20 14:23:23 +08:00
    @cnbatch #4 #4 感谢回复!这个塞入 std::initializer_list{} 的区别是不是就是左值和右值的区别? std::vector<Data> myDatas{Data{11}},也只会打印一次 Copy constructor 。 而一开始传的是个 data 变量,这是个左值,所以会复制多一遍。
    cnbatch
        6
    cnbatch  
       2022-07-20 14:42:30 +08:00
    @frankmdong 没错,就是左值和右值的缘故
    pocarisweat
        7
    pocarisweat  
       2022-07-21 00:03:57 +08:00
    @frankmdong
    这里的副作用指的是调用了外部函数来 print ,如果没有这个外部调用,编译器能很容易知道它啥也没做然后就能优化掉。
    frankmdong
        8
    frankmdong  
    OP
       2022-07-21 00:44:29 +08:00
    @pocarisweat #7 #7 懂啦,看来老哥只在凌晨刷 v 站
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1541 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 16:28 PVG 00:28 LAX 08:28 JFK 11:28
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86