这将执行默认移动操作吗?

Will this do default move operation

本文关键字:操作 移动 默认 执行      更新时间:2023-10-16

我有一个函数foo:

std::vector<T> foo() {
std::vector<T> result;
// populate result
{
/*
for loop with result.push_back().
ignore real code.
*/
}
//
return result;    <-- note there without std::move
}

如果我像下面这样分配,它会做额外的复制吗?

const auto v = foo();   <-- will it move the vector by default?
const auto &v = foo();  <-- same question as above, assuming T is movable

我对第二种情况特别感兴趣,因为对于第一种情况,它是 编译器很可能知道将结果foo(( 移动到 v。

const auto &v = foo();

对于这种情况,foo(( 函数会创建一个临时结果。现在,由于 v 是引用,因此它无法将结果移动到 v。因此,它需要创建一个新副本。我的理解是对的吗?

通过应用 as-if 规则,允许编译器进行任何和所有不会更改程序可观察行为的代码转换

但是,copy_elision是as-if 规则的一个例外:编译器可以删除对移动和复制构造函数的调用以及对临时对象析构函数的匹配调用,即使这些调用具有可观察到的副作用。要见证这些副作用,您必须在编译时使用-fno-elide-constructors选项。

从copy_elision页面,我们应该看一下子句:

在 return 语句中,当操作数是非易失性的名称时 具有自动存储持续时间的对象,这不是函数 参数或 catch 子句参数,并且属于同一类 类型(忽略 CV 限定(作为函数返回类型。这 复制 elision 的变体称为 NRVO,"命名返回值 优化"。

当编译器看到以下结构时,它知道它是 NRVO 的候选项。

T FunctionName ( ... )
{
T a;
...
return a;
}

这与问题的代码结构相匹配。

std::vector<T> foo() {
std::vector<T> result;
// populate result
{
/*
for loop with result.push_back().
ignore real code.
*/
}
return result;
}

个案1 -

const auto v = foo();   <-- will it move the vector by default?

你所看到的不是移动语义,它只是NRVO。
所以这个问题在这里没有任何相关性。

案例2 -

const auto &v = foo();  <-- same question as above, assuming T is movable

T是否可移动并不重要。这里没有发生move
正在发生的概念const &可以绑定到临时的。

我们也会在 C++11 之前的编译器中实现相同的结果,它没有移动语义支持。

对于这两种情况,似乎都没有额外的副本,从这个链接可以看到