在C++中,对具有唯一id的对象执行复制/移动/赋值的正确方法是什么


/* Example.h file */
class Example {
public:
Example(const std::string& unique_id_, int attribute1_, int attribute2_,): 
unique_id(unique_id_), attribute1(attribute1_), attribute2(attribute2_){};
void set_attribute1(int attribute1_){ attribute1 = attribute1_; }
void set_attribute2(int attribute2_){ attribute2 = attribute2_; }
/* Deleting copy/move/assignment operators to make each instance unique */
Exercise_Data(const Exercise_Data&) = delete;
Exercise_Data(Exercise_Data&&) = delete;
Exercise_Data& operator= (Exercise_Data&) = delete;
Exercise_Data& operator= (Exercise_Data&&) = delete;
private:
const std::string unique_id;
int attribute1;
int attribute2;
}

目前,这是我的代码。在调用代码的多个位置,我希望能够编辑这个类的所有属性,unique_id除外。如果我添加了另一个属性,那么调用代码(在多个地方(必须经过编辑才能设置新的属性。

  1. 有没有一种好的方法可以允许编辑除唯一id之外的所有属性
  2. 是否可以重载赋值并移动运算符来执行此操作,同时仍然删除复制构造函数
  3. 有人有一个具有唯一id的类的好例子吗

是否有一种好的方法允许编辑除唯一id之外的所有属性?

只需确保id是私有的,并且永远不会返回对它的非常量指针/引用。确保成员函数不会修改id应该很简单。

是否可以重载赋值并移动运算符来执行此操作,同时仍然删除复制构造函数?

类可以移动,但不能复制。此类类型称为"仅移动"。

如果您希望保持成员常量,则无法实现移动操作。我建议反对const成员。

有人有一个具有唯一id的类的好例子吗?

std::unique_ptr本质上就是此类的一个示例。";id";表示由析构函数清理的某些唯一资源。

如果每个对象都有一个唯一的、永久的标识,那么你可能真的不支持复制——对象的副本应该与原始对象相同,在这种情况下,你说每个对象都应该是唯一的,所以有一个副本可能没有意义。

另一方面,搬家施工应更加合理。尽管ID从一个对象移动到另一个对象,但在给定的时间仍然只有一个对象具有给定的身份。

move ctor非常简单明了。只需像往常一样在成员初始化器列表中初始化您的成员,包括这样一个事实,即由于它是一个移动ctor,您希望从源中的unique_id移动:

Example(Example&& other) 
: unique_id(std::move(other.unique_id)) 
, attribute1(other.attribute1)
, attribute2(other.attribute2)  
{ 
}

理论上,您可能也应该在attribute1attribute2上使用std::move,但由于它们是int,因此通常不会有任何实际区别。

然后我们讨论一个有点无关紧要的问题:移动任务。由于我们已经将unique_id定义为const,我们不能只是复制它。要完成这项工作,我们首先销毁目标对象的当前内容,然后使用placementnew来进行从源到目标的移动构造:

Example &operator=(Example&& other) { 
this->~Example();
new (this) Example(std::move(other));
return *this;
}

这是因为const资格在破坏或施工期间没有影响,所以这基本上是我们执行任务的唯一方法。

以下是一个示例,展示了它的全部功能:

#include <string>
#include <new>
#include <iostream>
class Example {
public:
Example(const std::string& unique_id_, int attribute1_, int attribute2_): 
unique_id(unique_id_), attribute1(attribute1_), attribute2(attribute2_){};
void set_attribute1(int attribute1_){ attribute1 = attribute1_; }
void set_attribute2(int attribute2_){ attribute2 = attribute2_; }
/* Deleting copy/move/assignment operators to make each instance unique */
Example(const Example&) = delete;
Example& operator= (Example&) = delete;

Example(Example&& other) 
: unique_id(std::move(other.unique_id)) 
, attribute1(other.attribute1)
, attribute2(other.attribute2)  
{ 
}
Example &operator=(Example&& other) { 
this->~Example();
new (this) Example(std::move(other));
return *this;
}
private:
const std::string unique_id;
int attribute1;
int attribute2;
friend std::ostream &operator<<(std::ostream &os, Example const &e) { 
return os << "ID: " << e.unique_id;
}
};
int main() { 
Example a("A", 1, 2);
std::cout << "A: " << a << "n";
Example b{std::move(a)}; // move construction
std::cout << "B: " << b << "n";
Example c("B", 3, 4);   // construct a destination object
c = std::move(b);       // move assign into it
std::cout << "C: " << c << "n";
}

关于对象中唯一id的真实例子。。。如果不重新搜索代码,我不确定。我记得有几个看起来至少很接近(当然还有其他有const成员的成员,他们使用相同的销毁/放置新的"技巧"来完成任务(,但我没有足够的雄心去仔细查看它们,以检查是否有与此完全相同的。

最新更新