返回值优化:我可以避免复制庞大的STL容器。

时间:2015-11-06 08:50:29

标签: c++ rvo

当我想要一个函数给我一个容器时:

vector<T> result = func(); 

以下列方式使用:

void func(vector<T>& result){
    result.clear();
    ...
    result;
}

为了避免复制我的容器的开销 我经常写这个函数,除了接受a之外​​什么也不返回 容器的非const实例。

vector<T> result;
func(result); 

以下列方式使用:

while (true) {
    int n = sc.read(byteBuffer);
    if (n > 0) {
        byteBuffer.flip();
        CharBuffer cbuf = charset.decode(byteBuffer);
        while (cbuf.hasRemaining()) {
            char c = cbuf.get();
            if (c == '\r' || c == '\n') break;
            incomingClientMessage.append(c);
        }
    }

我的努力没有意义,因为我可以肯定编译器 总是使用返回值优化?

4 个答案:

答案 0 :(得分:10)

没有意义。您提到的RVO类型称为RVO(NRVO),大多数编译器都会实现它。

无论如何,在C ++ 11中,vector具有移动构造函数,因此即使NRVO不适用,它仍然会被移动,而不是被复制。

答案 1 :(得分:2)

RVO无法保证,但正常的编译器会在允许的情况下使用它。

但问题是RVO只在您在函数外部创建新对象时才有帮助。如果通过引用传递相同的向量来重用它,则可以利用其保留的容量来减少内存分配的数量。无论在何处存储返回值,在函数内部创建的局部向量总是需要在内部分配新的缓冲区。因此,通过引用传递向量可能更有效,即使代码看起来不太好。

答案 2 :(得分:2)

取决于编译器的年龄。在C ++ 11之前,除非编译器支持命名的返回值优化,否则您需要的替代方法 - 并非所有旧编译器都支持。此外,您还可以让函数返回对传递的向量的引用。

从C ++ 11开始,该语言支持移动构造,标准容器具有工作移动构造函数,因此您的第一种方法很好。纯粹主义者会坚持认为这更好。实用主义者(他们意识到并非每个人都可以在没有巨大影响的情况下更新他们的编译器)会说选择一个解决方案,这取决于你的代码是否需要继续使用混合的前C ++ 11和更高版本的编译器。

答案 3 :(得分:0)

我用gcc试过了。我意识到在没有C ++ 11标志的情况下编译时我不能依赖NRVO。

由于我不喜欢第二个签名(函数通过引用获取容器),我出来了:

以自然形式声明函数:

vector<T> func(){
    vector<T> result;
    ...
    return result; 
}

并且,当我不确定编译器和编译标志时,请以这种方式使用它:

vector<T> result;
func().swap(result)

以这种方式获得所需的接口,并确保避免有利的开销。

请注意,result向量的容量是函数返回的向量之一。如果想要设置向量的容量,则该函数的右侧接口是第二个。