【问题标题】:Implementing move constructor in C++在 C++ 中实现移动构造函数
【发布时间】:2021-08-15 13:28:15
【问题描述】:

我创建了以下类:

class CList
{
private:
    Cust *custArray{new Cust [1]}; 
    size_t arrayCap{1};                  
    size_t used{0};                       
    // also, the number of used cells
public:
    CList() = default;
    CList(CList&&);  

class Cust
{

private:
    const char *name;
    const char *email;
    size_t id;

public:
    Cust()
    {
    }
    Cust(const char *_name, const char *_email, size_t _id)
    {
        name = _name;
        email = _email;
        id = _id;
    }
};

我需要帮助来实现CList(CList&&) 移动构造函数。它会简单地创建传递的对象的副本吗?

【问题讨论】:

  • 移动构造函数,就像它说的那样,不要复制任何东西。它们移动值,使传递的对象处于未指定状态。
  • CList(CList&& x) : custArray{std::exchange(x.custArray, nullptr}, arrayCap{std::exchange(x.arrayCap, 0)}, used{std::exchange(x.used, 0)} { }
  • 如果没有必要,不要手动分配内存。如果你使用向量,你可以有:class CList { private: std::vector<Cust> custArray; public: CList() = default; CList(CList&&) = default; };

标签: c++ move-constructor


【解决方案1】:

移动构造函数通常将资源传输到新对象,而不是复制它们。这种传输通常只涉及复制句柄(指针、文件描述符或其他),而不是句柄引用的任何资源。完成此操作后,构造函数确保移出对象不引用任何资源(即句柄为空或无效或其他)。例如:

CList(CList&& other) {
   custArray = other.custArray; // copy the handle
   arrayCap = other.arrayCap;   // copy supporting information
   used = other.used;           // copy supporting information
   other.custArray = nullptr;   // zero out the old handle
}

您可能应该在实际代码中使用std::exchange。更重要的是,在实际代码中,您应该使用 std::vector 而不是手动分配的数组,这样就完全不需要手写移动构造函数了。

【讨论】:

  • if (this == &other) return; 会发生吗?该对象刚刚在构建中,这意味着它不能用于移动到自身,除非你写CList foo = std::move(foo);
  • 这似乎与重载赋值运算符operator= 完全相同。这两者有什么区别吗?
  • @joseph 这似乎与重载赋值运算符 operator= 完全一样,不,这些东西非常不同。
  • @joseph 存在显着差异。构造函数创建以前不存在的对象。赋值是改变现有对象的状态,在获取新状态之前可能必须先清理旧状态。赋值通常也会返回对 self 的引用。但是,在 move-ctor 和 move-assignment 运算符之间,移动对象的情况大致相同。
  • 编写移动构造函数和移动赋值运算符通常一起完成。如果存在一个,那么另一个可能也是需要的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-03
  • 2018-01-23
  • 2012-05-11
  • 1970-01-01
  • 1970-01-01
  • 2018-10-17
相关资源
最近更新 更多