4

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

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

我想可以如下定义一个 stl 实例(没有错误):

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

但是这样做有效率吗?

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

4

2 回答 2

5

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

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。

如果您的编译器不应用 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&&(即移动构造函数和赋值运算符的参数)不会绑定到 const 右值参数(即函数的返回值)。这有效地使您的代码在 C++98/03 下运行(即具有 2 或 3 个堆分配)。

于 2013-01-10T10:39:17.907 回答
1

这是罚款和合法的代码。编译器将通过复制省略
来处理必要的优化(如果可以的话)。

临时f(...)保证至少在表达式结束之前存在。请注意,表达式在 return from 之后结束stl_instance(f(...)),准确地说是;在 call 结束时的分号)。所以它是完全有效的。

C++03 标准§12.2/3:

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

于 2013-01-10T04:52:45.723 回答