zoukankan      html  css  js  c++  java
  • copy elison & RVO & NRVO

    蓝色的博文

    To summarize, RVO is a compiler optimization technique, while std::move is just an rvalue cast, which also instructs the compiler that it's eligible to move the object. The price of moving is lower than copying but higher than RVO, so never apply std::move to local objects if they would otherwise be eligible for the RVO.

    因此,在能够使用copy elision时,我们不要在return时加std::move()。在copy elision不work时,我们还是要加上std::move()从而调用move constructor而不是调用copy constructor.

    博文中比较费解的是最后一个示例,这么写似乎产生了bug。

    个人理解:最后一个示例触发了RVO,导致第一次拷贝:栈内变量拷贝至返回值临时变量被省略(两次拷贝参见下文),第二次拷贝:临时变量拷贝至具名变量未省略。而因为变量类型是右值引用,第二次的拷贝变成了移动构造。于是就出现了奇怪的输出。

    Copy elision

    In general, the C++ standard allows a compiler to perform any optimization, provided the resulting executable exhibits the same observable behaviour as if (i.e. pretending) all the requirements of the standard have been fulfilled. This is commonly referred to as the "as-if rule".[8] The term return value optimization refers to a special clause in the C++ standard that goes even further than the "as-if" rule: an implementation may omit a copy operation resulting from a return statement, even if the copy constructor has side effects.[1]

    The following example demonstrates a scenario where the implementation may eliminate one or both of the copies being made, even if the copy constructor has a visible side effect (printing text).[1] The first copy that may be eliminated is the one where a nameless temporary C could be copied into the function f's return value. The second copy that may be eliminated is the copy of the temporary object returned by f to obj.

    #include <iostream>
    
    struct C {
      C() {}
      C(const C&) { std::cout << "A copy was made.
    "; }
    };
    
    C f() {
      return C();
    }
    
    int main() {
      std::cout << "Hello World!
    ";
      C obj = f();
      return 0;
    }

    Depending upon the compiler, and that compiler's settings, the resulting program may display any of the following outputs:

    Hello World!
    A copy was made.
    A copy was made.
    Hello World!
    A copy was made.
    Hello World!

    这里有一篇博文,结合了《深度探索C++对象模型》,博文链接

    在g++中开启选项-fno-elide-constructors可以去掉任何返回值优化,则C obj = f(); 中,会发生两次拷贝,f()内栈内变量拷贝构造返回值临时变量,返回值临时变量拷贝构造obj变量。

    这里有一份更详细点的文档...

    https://en.cppreference.com/w/cpp/language/copy_elision

    ===============================================================

    最后是关于push_back与emplace_back的测试。

    T &&var1 = std::move(var2); 不存在移动拷贝。

    template< class... Args >
    void emplace_back( Args&&... args );通过std::forward<Args>(args)...实现。
     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 struct Stu {
     4     int age;
     5     Stu(const int age = 0):age(age) {
     6         cout << "construct" << endl;
     7     }
     8     Stu(const Stu& s){
     9         cout << "copy construct" << endl;
    10     }
    11     Stu(Stu&& s) {
    12         cout << "move construct" << endl;
    13     };
    14     Stu& operator = (const Stu& s) {
    15         cout << "operator construct" << endl;
    16     }
    17     ~Stu(){
    18         cout << "destruct" << endl;
    19     }
    20 };
    21 
    22 Stu Init(const int age) {
    23     return Stu(age);
    24 }
    25 
    26 int main() {
    27     Stu s1(26);
    28     cout << "1--------------" << endl;
    29     Stu s2 = Init(20);
    30     cout << "2--------------" << endl;
    31     vector<Stu> ve;
    32     ve.reserve(10);
    33     cout << "3--------------" << endl;
    34     ve.push_back(s1);
    35     cout << "4--------------" << endl;
    36     Stu&& ss = std::move(s1);
    37     ve.push_back(std::move(s1));
    38     cout << "5--------------" << endl;
    39     ve.emplace_back(Stu(3));
    40     cout << "6--------------" << endl;
    41     ve.emplace_back(3);
    42     return 0;
    43 }
    44 
    45 /*
    46 construct
    47 1--------------
    48 construct
    49 move construct
    50 destruct
    51 move construct
    52 destruct
    53 2--------------
    54 3--------------
    55 copy construct
    56 4--------------
    57 move construct
    58 5--------------
    59 construct
    60 move construct
    61 destruct
    62 6--------------
    63 construct
    64 destruct
    65 destruct
    66 destruct
    67 destruct
    68 destruct
    69 destruct
    70 */
    View Code
  • 相关阅读:
    针对动态加载方式的C/C++动态链接库编写
    Delphi无法正确动态调用C++ dll库的几个原因
    Windows下VC++显示UTF-8编码中文
    小型C/C++项目的makefile编写
    树状树组(Binary Indexed Tree (BIT))的C++部分实现
    PLSQL创建Oracle定时任务
    Oracle:trunc()函数简介 时间处理及数字小数位处理
    Chrome inspect学习(四)本地环境/测试环境前端与客户端交互,涉及客户端代码报错,如何调试
    Chrome inspect学习(三)如何查看本地环境/测试环境下移动端内嵌H5页面在手机中真实渲染的DOM结构、CSS样式、接口调用
    Chrome inspect学习(二)如何查看线上环境移动端内嵌H5页面在手机中真实渲染的DOM结构、CSS样式、接口调用
  • 原文地址:https://www.cnblogs.com/dirge/p/10389996.html
Copyright © 2011-2022 走看看