我有两个类似的方法,它们都通过引用获取 std::vector ,然后其中一个尝试通过引用返回它(因为生命周期得到满足),另一个通过 move 返回。在这两种情况下,我都不需要之后传递的 vector ,这只是为了满足语法要求。
这两个功能看起来像 -
std::vector<unique_ptr<Item>> func_returns_move(std::vector<unique_ptr<Item>> &items) {
items.erase(std::remove_if(items.begin(), items.end(),
[&](const std::unique_ptr<Item> &item) {
return item->age > 20;
}), items.end());
return move(items);
}
std::vector<unique_ptr<Item>>& func_returns_ref(std::vector<unique_ptr<Item>> &items) {
items.erase(std::remove_if(items.begin(), items.end(),
[&](const std::unique_ptr<Item> &item) {
return item->age > 20;
}), items.end());
return items;
}
根据我的假设,这里应该没有太大区别,因为唯一不同的线是最后一条 - 一个由 ref 返回,另一个直接 move 。起初我想可能是因为 move 创建了一个临时对象,默认情况下它可能会 malloc 或其他东西,这将是
result = func_returns_move(...)
之类的函数的结果,但它应该是恒定时间,这里不是这种情况。花费的时间与 vector 中的元素数量成正比。所以我无法理解是什么导致了 std::move 案例的更多执行作为返回。时间如下——
FUNC_RETURNS_MOVE: 50
FUNC_RETURNS_REF: 5
测试程序在这里 - https://godbolt.org/z/5Y8Mcw
最佳答案
在第二种情况下, vector 在范围退出时被销毁(唯一的 vector 对象是 items2
)。这超出了您的限时区域。
然而,在第一种情况下,返回的 move 构造 vector 临时在完整表达式的末尾被销毁,它在计时部分内。 items1
仍然在作用域退出时被销毁,但此时它是空的。
两种情况的实际时间成本基本相同。但是在第一种情况下,所有元素的销毁都在定时区域内,而在第二种情况下,它在定时区域外。
如果我们将返回的 vector 对象的销毁保持在计时之外,我们会在两者之间得到一致的结果(并且可以看到 move 确实是“自由”的):https://godbolt.org/z/z-wKVG
(由于技术许可的原因,我不会在这里复制相关的 Godbolt 代码 - 它需要在问题中。)
关于c++ - 为什么通过引用返回 vector 比通过 move 返回快得多?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/58301058/