返回值优化与大向量的auto_ptr
return value optimization vs auto_ptr for large vectors
如果我使用 auto_ptr 作为填充大向量的函数的返回值,这将使该函数成为源函数(它将创建一个内部auto_ptr并在返回非常量auto_ptr时传递所有权(。但是,我不能将此功能与 STL 算法一起使用,因为为了访问数据,我需要取消引用auto_ptr。我想一个很好的例子是一个大小为 N 的向量字段,每个向量有 100 个分量。如果 N 很大,函数是否按值返回每个 100 个分量向量或按 ref 返回都不相同。
另外,当我尝试这个非常基本的代码时:
class t
{
public:
t() { std::cout << "ctor" << std::endl; }
~t() { std::cout << "dtor" << std::endl; }
};
t valueFun()
{
return t();
}
std::auto_ptr<t> autoFun()
{
return std::auto_ptr(new t());
}
自动娱乐和娱乐调用都以输出结果产生
克托尔多尔
所以我实际上看不到正在创建的自动变量传递给 return 语句。这是否意味着为 valueFun 调用设置了返回值优化?在这种情况下,valueFun会创建两个自动对象吗?
那么,如何使用函数优化如此大的数据结构的总体?
这有很多选择,动态分配可能不是最好的。
在我们深入研究这个讨论之前: 这是一个瓶颈吗?
如果您没有剖析并确保它是一个瓶颈,那么这个讨论可能会完全关闭......请记住,分析调试版本几乎毫无用处。
现在,在 C++03 中,有几种选择,从最可口到最不可口:
- 信任编译器:例如,未命名变量即使在 gcc 的调试版本中也使用 RVO。
- 使用"out"参数(通过引用传递(
- 在堆上分配并返回指针(智能与否(
- 检查编译器输出
就个人而言,我会信任我的编译器,除非分析器证明我错了。
在 C++11 中,移动语义帮助我们变得更加自信,因为只要有return
语句,如果 RVO 无法启动,那么移动构造函数(如果可用(可以自动使用;移动构造函数vector
非常便宜。
所以它变成了:
- 信任编译器:RVO 或移动语义
- 在堆上分配并返回
unique_ptr
但实际上第二点应该只用于移动语义没有多大帮助的少数类:移动语义的成本通常与sizeof
的返回成正比,例如std::array<T,10>
的大小等于 10*sizeof(T)
所以它不是那么好,可能会从堆分配 + unique_ptr
中受益。
切线:你已经信任你的编译器了。你相信它会警告你错误,你相信它会警告你危险/可能不正确的结构,你相信它会正确地将你的代码翻译成机器组装,你相信它会应用有意义的优化来获得体面的加速......不信任编译器在明显的情况下应用 RVO 就像不信任您的心脏外科医生提供 10 美元的钞票一样:这是您最不担心的事情。;)
我相当确定编译器将为valueFun进行返回值优化。编译器无法应用返回值优化的主要情况是:
- 返回参数
- 基于条件返回不同的对象
因此,auto_ptr不是必需的,并且由于必须使用堆而更慢。
如果您仍然担心在如此大的向量周围移动的成本,您可能需要考虑使用 C++11 的移动语义(std::vector aCopy(std::move(otherVector))
。这些几乎与 RVO 一样快,可以在任何地方使用(当 RVO 无法使用时,它也保证用于返回值。
我相信大多数现代编译器在这一点上都支持移动语义(或技术上的右值引用(
- 在for循环中使用auto vs decltype(vec.size())来处理字符串的向量
- CLANG 编译器 说:变量"PTR"可能未初始化
- 如何在自定义类中启用'auto loops'?
- 当我在第一个循环中使用"auto"时,它工作正常,但是使用"int"它会给出错误,为什么?
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 为共享 ptr 向量实现复制 c'tor?
- 为什么当我为 for(auto& it : myUnorderedMap) {... = std::move(it.second)} 时,我会得到一个 const 引用?
- 字符和整数中 **(ptr+1) 的值差异
- C++:在不中断共享的情况下通过引用传递共享 PTR?
- 为什么结构化绑定不使用"auto&"返回对结构成员的引用,而是返回成员本身
- 擦除许多矢量元素,同时使用'auto'
- 考虑到其他好处,关键字'auto'真的有助于简化调试C++吗?
- 为什么"weak.lock()"返回"nullptr" "auto weak=std::make_shared<int>(42);"的定义?
- 推理类型如何工作"auto"和按引用调用?
- 如何将派生类从基 ptr 分配给 nlohmann::json
- 引用 std::shared:ptr 以避免引用计数
- 'auto *x = new some_struct{};"是一个未初始化的变量?
- 为什么 std::gcd/lcm 返回 std::common_type_t<M, N> 而不是 auto?
- 将函数参数类型声明为 auto