c++函数返回临时变量和局部变量,有什么区别? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
amiwrong123
V2EX    C++

c++函数返回临时变量和局部变量,有什么区别?

  •  
  •   amiwrong123 2022-01-24 19:07:13 +08:00 3062 次点击
    这是一个创建于 1408 天前的主题,其中的信息可能已经有所发展或是发生改变。
    #include <iostream> using namespace std; class A { public: A() { cout << "default constructor" << endl; } A(const A& x) { cou << "copy constructor" << endl; } A(A&& x) { cout << "move constructor" << endl; } A& operator = (const A& x) { cout << "copy assigment operator" << endl; return *this; } A& operator = (A&& x) { cout << "move assigment operator" << endl; return *this; } }; A returnValue() { return A(); } A returnValue_1() { A a; return a; } A&& returnValue_2() { return A(); } int main() { A e = returnValue(); // move constructor cout << endl; A e1 = returnValue_1(); // move constructor cout << endl; A e2 = returnValue_2(); // move constructor return 0; } /* default constructor default constructor move constructor default constructor move constructor 

    A e = returnValue();只打印了一句,我理解执行A()打印了 default constructor ,然后 return 时经过 RVO 优化,就少打印一次。然后经过 https://en.cppreference.com/w/cpp/language/copy_initialization 里面提到的 纯右值的优化,又少打印一次。

    A e2 = returnValue_2();打印两次是因为:执行A()打印了 default constructor ,然后 return 时经过 RVO 优化,就少打印一次。但由于函数返回值类型为 A&&,作为 亡值,就必须调用 移动构造函数。

    但 A e1 = returnValue_1();为什么打印这两句阿?(它的返回值类型就是 A ,不是 A&&啊)

    顺便问下,移动赋值操作符这里的提示是啥意思呀

    (上面说的理解,如果有问题也请指正)

    10 条回复    2022-01-26 00:50:38 +08:00
    nlzy
        1
    nlzy  
       2022-01-24 19:23:22 +08:00 via Android
    https://zh.cppreference.com/w/cpp/language/return

    自动从局部变量和形参移动
    lovelylain
        2
    lovelylain  
       2022-01-24 19:30:50 +08:00
    returnValue_1 是 NRVO ,Named Return Value Optimization 具名返回值优化,简单说就是编译器会尽可能给你做返回值优化,减少拷贝。
    amiwrong123
        3
    amiwrong123  
    OP
       2022-01-24 21:09:37 +08:00
    @jobmailcn #2
    优化的话,不应该是连 移动构造函数 都不用调用了吗?(就只用打印一句了)
    不过 从 复制构造函数 改成 移动构造函数,也是 进行优化了。
    v2byy
        4
    v2byy  
       2022-01-24 21:19:54 +08:00
    @amiwrong123 使用 vs2019 release 模式下,确实 returnValue1 只调用了 default ctor
    woodpenker
        5
    woodpenker  
       2022-01-24 21:33:28 +08:00
    编译器无法确一定能优化 NRVO 场景, 只能先放栈帧中再移出到调用方. 优化过的编译器识别到这种只有一个确定的命名返回值时就可以把 move 优化掉.
    amiwrong123
        6
    amiwrong123  
    OP
       2022-01-24 21:38:40 +08:00
    @v2byy #4
    真的哎,release 模式 居然不一样,这是为啥
    ysc3839
        7
    ysc3839  
       2022-01-24 21:48:29 +08:00 via Android
    @amiwrong123 因为 Debug 禁用了优化。
    比如你这段代码,Release 下的优化可能直接把 cout << "default constructor" << endl; 内联到 main 里面了,调试时你可能想 step into returnValue_1(),结果发现直接“跳过”了这个函数,Debug 模式会禁用优化,便于调试。
    statumer
        8
    statumer  
       2022-01-24 22:03:59 +08:00   2
    建议你了解一下 copy elision
    对哪些优化是强制性,哪些优化是非强制性的解释得很明确了。
    现在你写的第一种是标准要求的 guaranteed copy elision 了,满足 copy elision 规则所以只调用默认构造函数(并不是两次优化)。
    你写的第二种是非强制的 copy elision ,所以编译器可以自行决定是 RVO 还是 copy/move 。
    你写的第三种应该是不合法的,A()是临时对象会被分配到栈上,returnValue_2 返回了一个栈上对象的引用。严重时会导致段错误。

    https://en.cppreference.com/w/cpp/language/copy_elision
    amiwrong123
        9
    amiwrong123  
    OP
       2022-01-25 00:41:05 +08:00
    @statumer #8
    > 现在你写的第一种是标准要求的 guaranteed copy elision 了,满足 copy elision 规则所以只调用默认构造函数(并不是两次优化)。
    那是不是也可以理解为 有两次 copy elision ,return 时一次,初始化变量时一次。

    >你写的第三种应该是不合法的,A()是临时对象会被分配到栈上,returnValue_2 返回了一个栈上对象的引用。严重时会导致段错误。
    我记得不是有一种,引用可以延长临时变量生命周期的东西?这样是不是就是合法的 了。

    另外,看 cppreference 总感觉有些话看不懂:
    >即使复制 /移动构造函数和析构函数拥有可观察的副作用
    这句啥意思阿,啥叫可观察的副作用

    struct C { /* ... */ };
    C f();
    struct D;
    D g();
    struct D : C {
    D() : C(f()) { } // 初始化基类子对象时无消除
    D(int) : D(g()) { } // 无消除,因为正在初始化的 D 对象可能是某个其他类的基类子对象
    };
    >无消除,因为正在初始化的 D 对象可能是某个其他类的基类子对象
    它是说 D(g())这里吗,这里看起来是调用了一个 委托构造函数,正在初始化的 D 对象怎么可能是某个其他类的基类子对象呢?( D 也没有派生类阿。。)
    agagega
        10
    agagega  
       2022-01-26 00:50:38 +08:00
    @amiwrong123
    可观察的副作用就是说有一个操作在那,限制了你没法做优化。举例:妈妈让小明下楼走一圈,小明可以出门坐一会然后给妈妈说自己走过了;但如果妈妈让小明下楼走一圈并买瓶酱油,小明就没有办法偷懒必须得下去了。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5534 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 37ms UTC 03:09 PVG 11:09 LAX 19:09 JFK 22:09
    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