• C++ 返回值优化及移动语义


    局部变量unique_ptr能否作为返回值

    记得自己之前在哪写过一篇返回值优化的博客,翻了半天csdn,居然没找到,也不知道写在哪了。被问到一个unique_ptr 局部变量能不能做返回值的问题,想当然说因为拷贝构造被delete不行,果然我还是unique_ptr 用的不多,只用来pimpl了。想起来真是被自己蠢笑了。在这里插入图片描述

    左值、右值、将亡值

    先了解一下左右值、将亡值的概念,概念就不抄了

    class A {
      public:
        int a;
    };
    A getTemp()
    {
        return A();  //右值
    }
    A a = getTemp();//a左值,gettemp()返回值右值
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    可以看到,按照理想情况,我们其实会一次构造加+两次拷贝构造,还有多个临时对象的析构,但是我们只要实际长期使用的只是为了为了构建一个a变量使用而已,花销太大,因此c++11 引入了移动语义以及RVO机制(RVO c++11 编译器都有,但并不是是语言标准强规范,c++17起才在规范做了强制要求),减少无用的拷贝构造和析构。

    跑个实际的例程吧

    #include 
    #include 
    using namespace std;
    
    class Test {
    public:
        Test() {
            cout << "Create" << endl;
        }
        Test(const Test &o) {
            cout << "Copied" << endl;
        }
    
        Test(const Test &&o) {
            cout << "Move" << endl;
        }
        ~Test() {
            cout << "Destroy" << endl;
        }
    };
    Test ReturnRvalue() {
        return Test();  //RVO优化,函数返回值的地址就是test右值分配的地址,没有做赋值及移动拷贝
    }
    
    Test ReturnRvalue1() {
        auto temp = Test();
        return temp;    //NRVO优化,函数返回值的地址就是test右值的地址,没有做赋值及移动拷贝
    }
    void AcceptVal(Test a) {}
    void AcceptRef(const Test &a) {}
    
    int main() {
        cout << "pass by value: " << endl;
        AcceptVal(ReturnRvalue());
        cout << "pass by value1: " << endl;
        AcceptVal(ReturnRvalue1());
        cout << "pass by reference: " << endl;
        AcceptRef(ReturnRvalue());
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    输出如下,节省了复制/移动拷贝,只进行了一次构造

    pass by value:
    Create
    Destroy
    pass by value1:
    Create
    Destroy
    pass by reference:
    Create
    Destroy
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    接下来禁用返回值优化 -fno-elide-constructors (gcc选项,msvc没找到)

    pass by value: 
    Create
    Move
    Destroy
    Move
    Destroy
    Destroy
    pass by value1: 
    Create
    Move
    Destroy
    Move
    Destroy
    Move
    Destroy
    Destroy
    pass by reference: 
    Create
    Move
    Destroy
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    值得注意的是,返回值调用在例程中仍然调用的是移动构造

    Test ReturnRvalue1() {
        auto temp = Test();
        return temp;    //禁用RVO仍是调用移动构造
    }
    
    • 1
    • 2
    • 3
    • 4

    这是也是c++11引入的一个优化,但查了下他居然不叫返回值优化。

    cpprefence

    在这里插入图片描述
    字面意思就是,某些自动存储周期(函数参数、函数体)的局部变量做返回值时,重载决议两次,先移动构造,再拷贝构造。

    所以即使不考虑RVO 以下两种都是语法上都是合法的

    std::unique_ptr<int> questionA(){
        auto t = make_unique<int>(99);
        return t;
    }
    
    std::unique_ptr<int> questionB(std::unique_ptr<int> t){
        return t;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    2021 华数杯全国大学生数学建模竞赛C题-电动汽车目标客户销售策略研究(一)(附带赛题解析&获奖论文及Python代码)
    制作一个简单HTML电影网页设计(HTML+CSS)
    计算机毕业设计Java易医就医购药交互平台(源码+系统+mysql数据库+Lw文档)
    PHORHUM(CVPR2022)-3D重建论文解读
    智慧公厕设备选型攻略,打造智能化便利生活体验
    JC/T 482-2022 聚氨酯建筑密封胶检测
    ACCESS_MASK不明确的符号
    时空数据挖掘一(城市计算)
    Compose原理-compose中是如何实现事件分法的
    <Java编程工具JDK、IDEA安装及环境配置教程>——《Java》
  • 原文地址:https://blog.csdn.net/weixin_43862847/article/details/126594407