【问题标题】:How move constructor works in C++?移动构造函数如何在 C++ 中工作?
【发布时间】:2018-06-26 10:02:47
【问题描述】:

我已经阅读了很多关于移动构造函数的文章(甚至在堆栈上),但我没有找到任何关于它如何工作的确切解释(如何将指针传输到临时对象并保存如果这个临时变量及其地址将是遇到时销毁")")。

这是一个简单的例子

#include <iostream>
#include <vector>
using namespace std;
class boVector {
private:
    int size;
public:
    boVector() {};
    boVector(const boVector& rhs) { cout << "copy Ctor." << endl; }
    boVector(boVector&& rhs) { cout << "move Ctor." << endl; }
};

void foo(boVector v) {}
boVector createBoVector() { return boVector(); }

int main()
{
    //copy
    boVector reausable = createBoVector();
    foo(reausable);
    //move
    foo(std::move(createBoVector()));
    return 0;
}

都说移动Ctor是一个浅拷贝拷贝或者只是一个指针赋值。但是我怎样才能用一个指向临时对象的指针来启动我的对象(当这个对象将被销毁时,我的对象将指向一个未知的地址,从我的角度来看这是无效的)。

用他遇到“)”后将不再存在的指针地址来初始化一个变量是不对的。

如果有人可以解释一下这个临时变量在内存中的外观,以及如何将临时对象的地址分配给我当前的地址,并且这个操作是有效的。

【问题讨论】:

标签: c++ c++11 constructor move-semantics move-constructor


【解决方案1】:

“移动构造函数”没有什么神奇之处——它是一个接受右值引用的构造函数。

右值引用绑定到临时对象,并具有即将过期且不会在程序中稍后访问的东西的“含义”:这使开发人员能够实现资源移动- 在指针交换或类似的快速操作方面持有类。

您的boVector 类不能真正利用移动语义,因为它只存储int 并且不保存任何资源。移动int 与复制一个一样快。


foo(std::move(createBoVector()));

表达式,std::move 是多余的,因为createBoVector() 已经是一个右值


考虑:

foo(createBoVector());

这将调用boVector(boVector&amp;&amp;),因为它比boVector(const boVector&amp;) 更匹配。

createBoVector() 创建的实例将在表达式的整个持续时间内存在 - 这意味着 右值引用 将在boVector(boVector&amp;&amp;) 的持续时间内指向一个有效对象。

【讨论】:

  • 我无法理解的是,如果这将被破坏,我如何将临时值绑定到我的对象。例如 boVector(boVector&& size) 临时对象以“(”开始存在并以“)”结束。如果在我的移动中,我会说 this.m_size = size。在 Ctor size 结束后不再存在,因此 m_size 也应该为空。
  • @Adrian 将被销毁的是 moved-from 对象,临时对象(将其视为移出后的空对象),而 不是 移动到 对象。
  • @Adrian this-&gt;m_size 不是参考。因此this-&gt;m_size = size 赋值会复制一份。复制之后,复制的对象发生的任何事情都不会影响m_size,因为它是一个单独的对象。
  • 所以这里的移动Ctor就像一个复制ctor?当我思考移动时,我在想,例如,如果我看到一块手表……我喜欢它,所以我接受它。如果手表会自我毁灭,那么拿它有什么意义。当我在考虑复制 ctor 时……好吧,我看到了我喜欢的手表,所以我按照你的手表制作了自己的手表,但没有自动破坏机制。
  • @Adrian 将移动视为移动对象的内容,而不是对象本身。从某种意义上说,原始对象本身并没有移动,而是消失了。 (更类似的情况是“如果手表不再放在桌子上,那么把它从桌子上拿走有什么意义”,我想你会同意这是一个奇怪的问题。)跨度>
【解决方案2】:

都说移动Ctor是浅拷贝或者只是指针赋值。

并非所有人都这么说,因为这不是真的。移动构造函数是您定义的。在您的示例中,您的移动 ctor 完全执行其他操作。与复制 ctor 相比,移动 ctor 的意义在于您知道另一个对象即将被销毁,因此您可以蚕食或移动其资源。

移动构造函数可能制作一个“浅拷贝”,尽管该术语是口语化的,而不是在 C++ 中明确定义的。 “只是一个指针赋值”——也许,可能,有时。

但是我怎样才能用一个指向临时对象的指针来启动我的对象(当这个对象将被销毁时,我的对象将指向一个未知的地址,从我的角度来看这是无效的)。

您(通常)不会使用 T* 类型的指针本身来初始化 T 类型的对象。你可以分配my_t = *my_t_ptr,或者如果你知道你可以“蚕食”my_t_ptr指向的T,因为它很快就会被删除,那么你可以分配my_t = std::move(*my_t_ptr)

你能给我一个更相关的例子[移动构造函数和复制构造函数之间有意义的区别]...?

“经典”示例是通过在堆上分配一些空间来构造 T。当您从另一个T 复制构造一个T 时,您别无选择,只能分配第二段内存;当您移动构建T 时,您可以:1。将指针从现有的T 复制到正在构建的T。 2.将现有T的成员指针设置为nullptr。在这种情况下,您只需要使用一个 T 的堆栈空间。

【讨论】:

  • @Adrian:在你的情况下 - 移动和复制 ctor 之间没有区别。事实上,整数的“浅拷贝”或整数结构与“深拷贝”相同。此外,在您的示例中,根本不会使用临时对象。
  • 你能给我一个更相关的例子,我们可以谈谈吗?
猜你喜欢
  • 1970-01-01
  • 2018-09-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-23
  • 2012-05-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多