美文网首页
C++ Copy Elision

C++ Copy Elision

作者: 1m0nster | 来源:发表于2019-09-29 12:24 被阅读0次

    介绍

    C++中有一个重要的优化,就是拷贝省略(copy elision)。
    他的定义是:对于值传递的语意表达,会省略去拷贝步骤。
    比如如下面的代码:

    struct Data {
        char* bucket;
        int bucketSize;
        Data(int size) {
            bucketSize = size;
            bucket = new char[bucketSize];
        }
        Data(const Data& d) {
            bucketSize = d.bucketSize;
            bucket = new char[bucketSize]
            memcpy(bucket, d.bucket, bucketSize);
        }
    };
    
    Data GetData() {
        Data d(10);
        // other process
        return d;
    }
    
    void main() {
        Data d = GetData();
    }
    

    按照传统意义上的流程,会有如下的步骤:

    1. 在函数GetData中,有一个局部变量
    2. 函数退出堆栈,会构造一个临时变量(拷贝构造或者是move构造)
    3. GetData中的局部变量析构
    4. 用临时变量调用Data的拷贝构造函数来初始化main函数中的局部变量
    5. 临时变量析构

    仅仅是一个简单的赋制操作,就会涉及到这么多的步骤,并且对CPU有很大的负载。总共做了3次构造,两次拷贝。而copy elision所做的就是减少这些步骤,减少拷贝。

    那么在加上了copy elision之后,会省去哪些步骤呢?

    1. GetData()函数的“局部”变量的构造
    2. 析构

    只有这两步。省去了copy构造的步骤,并且没有生成临时变量。这里的局部加上了一个引号,意思是并不是真的临时变量。他可能的实现是这个样子的。

    void GetData(Data *) {
    // manipulate Data ptr
    }
    
    void main() {
        Data d;
        GetData(&d);
    }
    

    NRVO

    以上的优化,就是所谓的copy elision中的一个variant---NRVO(named-return value optimization)

    RVO

    还有一种优化就是RVO(unnamed-return value optimization)
    类似的这样的

    Data unmanedGetData() {
        return Data();
    }
    

    函数中直接返回一个匿名变量也是这种优化。直接对目的变量做优化,不需要临时变量,不需要拷贝。

    注意事项

    这种优化只是c++ standard的一种建议(c++17之前,c++17做了强制要求),所以不能想当然的任务所有的编译器都做了这种优化。在使用这些优化之前,应该看一下编译器是否真的做了这些优化。

    后记

    我在网上看到了一些意见,说这种编译器“自作主张”的优化,是对程序员不友好的。我所以为,持这种想法的人是因为,编译器做了这种优化,就不会调用诸如构造函数这类函数了,那么这些函数所造成的side effect就不会生效。
    那么编译器做这种优化好不好呢。我认为是好的。本来像copy constructor这类的函数,从语意(semantic)而言就是一个纯粹的拷贝构造。在这些函数中间插入别的代码,产生了副作用(side effect)就造成了函数本身的不纯粹。这对于函数本身的理念是不相符的。所以我认为,编译器的这种优化是很好的。

    相关文章

      网友评论

          本文标题:C++ Copy Elision

          本文链接:https://www.haomeiwen.com/subject/updfpctx.html