关于从函数和移动返回大值的混淆
Confusion regarding returning large values from functions and move
我正在观看Scott Mayers,Herb Sutter和Andrei Alexandrescu在2011年C++和超越》中的一次小组讨论。在关于哪个c ++ 11(当时的c ++ 0x(功能人们会出错的问题中,Andrei提到,当从函数返回大值时,人们认为移动语义不会涉及成本是错误的。他是这么说的
我现在不会设计接口来按值返回大东西,因为 对于所有 R 值引用,将有 在很多情况下会出现不必要的副本 创建。 这一点不应该被遗忘。
我不设计,也不容忍设计返回的接口 按价值计算的大事,因为有一天有人会从 IT和分配将是低效的。
我不认为归还大东西的成本应该被遗忘 R 值引用获胜的后果。
赫伯对此阐述了以下内容:
我同意你的看法,但它们是两种不同的情况,一种是你是 生成一个新的结果,你知道你要把它放在某个地方, 这就是你通过非常量引用传入的地方,并有一个输出 参数,这就是 out 参数的用途。
在其他情况下,您有两个输入,您将 创造新的东西,它是按价值返回的,而不是相反的 out 参数的东西,但它按值返回而不是执行 笨拙的解决方法,今天容易出错,只是堆分配 返回指针,只是为了避免额外的副本。
这是怎么回事,我只是不明白这两个家伙的意思。安德烈所说的"从中分配"的成本有什么区别?赫伯的解释,也只是在我脑海中蹦蹦跳跳。谁能详细说明一下?
另请考虑以下代码:
vector<BigData> GetVector(int someIndex)
{
vector<BigData> toFill;
// some processing
// filling the vector
return toFill;
}
我认为移动语义将使上面的代码等同于将空向量作为 out 参数传递。难道不是这样吗?
这是视频的链接。以上几点是在41分钟左右的播放时间后做出的。
我读不懂赫伯、安德烈或斯科特的心思。(题外话:这些家伙——都非常有才华——都与阿波罗太空计划没有任何关系(他们视频的背景((。 但是,我可以添加一些对右值引用/移动语义的见解。
如果你有一个纯工厂函数,如:
vector<BigData>
GetVector(int someIndex)
{
vector<BigData> toFill;
// some processing
// filling the vector
return toFill;
}
然后一定要按值返回它。 今天的每个编译器都会做RVO,这意味着从GetVector
移动/返回的成本完全为零。
话虽如此,在一种情况下,这是不好的建议。 对于具有capacity()
概念的容器(如 std::string
和 std::vector
(或其他一些在不影响价值的情况下增加性能的资源,可能会有一些示例,您不想无偿丢弃该资源。
例如,考虑:
vector<BigData> data;
while (I_need_to)
{
data = GetVector(someIndex);
process(data);
}
在此示例中,每次通过循环时,GetVector
都会分配一个新的vector
,这可能会造成浪费,因为vector
具有可以在这样的循环中重用的容量。 考虑此重写:
void
GetVector(int someIndex, vector<BigData>& toFill)
{
toFill.clear();
// some processing
// filling the vector
return toFill;
}
// ...
vector<BigData> data;
while (I_need_to)
{
GetVector(someIndex, data);
process(data);
}
在此重写中,data
每次通过循环时仍会获得一个新值。 但不同的是,前一个循环的capacity()
被保存,并重新用于当前循环。 如果此循环所需的data.size()
小于前一个循环的data.capacity()
,则当前循环永远不需要重新分配。 减少堆的行程是提高效率的关键。 事实上,减少堆的行程是移动语义的全部内容。
我猜这就是视频中讨论的重点。
我应该强调:如果工厂函数不会在这样的循环中使用,或者如果工厂函数的返回类型不能利用以前的一些资源(如capacity()
(,那么使用 inOut 参数重写没有任何好处。
- 返回值优化:显式移动还是隐式
- 按值 C++ 返回时进行双倍移动
- 为什么协程的返回类型必须是可移动构造的?
- 返回标准::移动(m_field)还是返回m_field?
- 如何将不可移动和不可复制的函数返回值获取到数组中
- 为什么返回std::optional有时移动,有时复制
- 为什么函数返回不移动向量?
- 复制省略并在返回值中移动语义
- 是否可以通过使用移动/交换 c++11 来延长返回的临时变量的生命周期
- 移动语义与返回shared_ptr?
- 为什么通过引用返回向量比通过移动返回要快得多?
- 从函数返回元组时,将复制元组的参数,而不是移动元组参数
- 返回 *&object 时是否允许复制/移动省略?
- 了解函数返回对象的移动语义
- C++所有 AT 命令的短信返回错误 |PC<->通过蓝牙和winsocket的移动连接
- 为什么结构化绑定禁用RVO和移动返回语句
- 为什么在返回时将复制构造函数而不是移动构造函数
- 返回unique_ptr或只是移动对象
- 移动了 QT 项目,重命名文件夹和项目名称,Moc'ing 返回"'-I'之后缺少值"
- 通过移动分配从算术运算符过载中返回const值