我有一个返回 stl 容器的工厂函数:
const std::vector<int> f(...) {
std::vector<int> retval;
return retval;
}
我想可以如下定义一个 stl 实例(没有错误):
const std::vector<int> stl_instance(f(...));
但是这样做有效率吗?
临时stl对象是否直接分配给stl_instance
?
我有一个返回 stl 容器的工厂函数:
const std::vector<int> f(...) {
std::vector<int> retval;
return retval;
}
我想可以如下定义一个 stl 实例(没有错误):
const std::vector<int> stl_instance(f(...));
但是这样做有效率吗?
临时stl对象是否直接分配给stl_instance
?
返回 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 中,此代码将至少两次进入堆:
如果您的编译器不应用 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 个堆分配)。
这是罚款和合法的代码。编译器将通过复制省略
来处理必要的优化(如果可以的话)。
临时f(...)
保证至少在表达式结束之前存在。请注意,表达式在 return from 之后结束stl_instance(f(...))
,准确地说是;
(在 call 结束时的分号)。所以它是完全有效的。
C++03 标准§12.2/3:
临时对象被销毁作为评估完整表达式(1.9)的最后一步,该完整表达式(在词法上)包含它们被创建的点。