我有两个类似的方法,它们都通过引用获取 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/

10-11 23:05
查看更多