基于函数返回的stl容器构造效率

时间:2013-01-10 04:50:40

标签: c++ c++11 rvalue-reference move-semantics return-value-optimization

我有一个返回stl容器的工厂函数:

const std::vector<int> f(...) {
    std::vector<int> retval;
    return retval;
}

我想可以将stl实例定义为如下(无错误):

const std::vector<int> stl_instance(f(...));

但这样做有效吗?

临时stl对象是否直接分配给stl_instance

2 个答案:

答案 0 :(得分:5)

返回const rvalue是C ++ 11中的反模式。首先考虑返回非const rvalues:

std::vector<int> f(int n) 
{ 
    return std::vector<int>(n); 
}

int main() 
{ 
    std::vector<int> v; 
    v = f(3); 
} 

在C ++ 98/03中,此代码至少会进入堆两次:

  1. 在f内创建向量(如果RVO适用)
  2. 从f返回v。
  3. 如果您的编译器未应用RVO,则会获得3个堆分配。

    在C ++ 11中,只能获得1个堆分配:在f内创建向量。无论RVO如何,都会发生这种情况。原因是所有STL容器都有移动构造函数和移动具有签名

    的赋值运算符
    vector( vector&& other );
    vector& operator=( vector&& other );
    

    右值引用&&会将资源从创建函数内部直接移动到目标。但是,您的代码具有签名

    const std::vector<int> f(int n) 
    { 
        return std::vector<int>(n); 
    }
    

    将禁用移动语义,因为T&amp;&amp; (即移动构造函数和赋值运算符的参数)不会绑定到const rvalue参数(即函数的返回值)。这有效地使您的代码在C ++ 98/03下运行(即具有2或3个堆分配)。

答案 1 :(得分:1)

这是良好的法律代码 编译器将通过复制省略来处理必要的优化(,如果它可以)。

临时f(...)保证至少生效至表达式结束。请注意,表达式在从stl_instance(f(...))返回后结束,确切地说是;在调用结束时的分号)。所以它完全有效。

C ++ 03标准§12.2/ 3:

  

临时对象作为评估全表达式(1.9)的最后一步被销毁,该表达式(词法上)包含创建它们的点。