0

基于这篇文章,http://www.drdobbs.com/cpp/when-is-it-safe-to-move-an-object-instea/240156579#disqus_thread

以下代码不会调用移动构造函数:

void func()
{
    Thing t;
    work_on(t);
    // never using t variable again ...
}

以下代码将调用移动构造函数:

work_on(Thing());

原因是对于第一个代码片段,构造函数可能会保存构造对象的地址,并在以后使用它。

我的问题是:但是对于第二个代码片段,在 work_on 完成之前,临时对象仍然是活动的,基于 C++ 标准,所以作者也可以保存构造对象的地址,并在 work_on 函数中使用它。所以基于同样的原因,它也不应该调用移动构造函数,这没有意义吗?

4

2 回答 2

1
void func()
{
    Thing t;

    work_on(t);       // <--- POINT 1

    work_on(move(t)); // <--- POINT 2

    work_on(Thing()); // <--- POINT 3
}

tPOINT 1 处的表达式是lvalue.

move(t)POINT 2 处的表达式是xvalue.

Thing()第3 点的表达式是 a prvalue

基于表达式的此值类别,从重载集中选择最佳可行函数。

假设两个可用的功能是:

work_on(const Thing&); // lvalue reference version
work_on(Thing&&);      // rvalue reference version

Anlvalue将选择左值引用版本,并且永远不会绑定到右值引用版本。

xvalueor prvalue(统称为rvalues)将有效地绑定到任何一个,但如果可用,将选择右值引用版本作为更好的匹配。

在两个版本的实现内部work_on,参数基本相同。这样做的目的是右值引用版本可以假设参数是他们的修改或移动。所以它可能会在其参数上调用移动构造函数——而左值引用版本不应该。

所以假设我们有一些vector<Thing> V应该work_on将它们的参数添加到:

void work_on(Thing&& t)
{
    V.push_back(move(t));
}

void work_on(const Thing& t)
{
    V.push_back(t);
}

std::vector::push_back以与 类似的方式work_on重载,并且发生类似的重载决议. 在 的两个不同实现中push_back,右值引用版本将调用移动构造函数将值推送到其数组中,可能会破坏t. 左值引用版本将调用复制构造函数,保持t不变。

这种语言机制的主要目的只是跟踪变量(左值)、有意标记的过期值(xvalues)和临时值(prvalues)——因此我们知道何时可以安全地重用它们的资源(移动它们)以及何时可以复制他们。

于 2013-06-19T09:23:30.533 回答
0

你把所有的理由都弄错了。没有关于“保存地址”的内容。(任何人都可以通过随机存储地址来编写任何形式的严重损坏的代码。这不是论据。)

原因很简单,在第一个片段中,t继续存在并且可以使用,所以你不能离开它:

Thing t;

work_on(t);

t.x = 12;
foo(t);

然而,在第二个片段中,临时值Thing()只存在于这一行,直到完整表达式的结尾,因此在语句结束后没有人可以引用该值。因此,从对象移动(即变异)是完全安全的。

于 2013-06-19T08:40:39.153 回答