C++ 在C++;,对具有唯一id的对象执行复制/移动/分配的正确方法是什么?

C++ 在C++;,对具有唯一id的对象执行复制/移动/分配的正确方法是什么?,c++,copy-constructor,move-semantics,uniqueidentifier,assignment-operator,C++,Copy Constructor,Move Semantics,Uniqueidentifier,Assignment Operator,目前,这是我的代码。在调用代码的多个位置,我希望能够编辑该类的所有属性,唯一的_id除外。如果我添加另一个属性,则必须编辑调用代码(在多个位置),才能设置该新属性 是否有一种好方法允许编辑除唯一id之外的所有属性 是否可以重载赋值并移动运算符来执行此操作,同时仍然删除复制构造函数 谁有一个具有唯一ID的类的好例子 是否有一种好方法允许编辑除唯一id之外的所有属性 只需确保id是私有的,并且永远不会返回对它的非常量指针/引用。确保成员函数不修改id应该很简单 是否可以重载赋值并移动运算符来执行此操

目前,这是我的代码。在调用代码的多个位置,我希望能够编辑该类的所有属性,唯一的_id除外。如果我添加另一个属性,则必须编辑调用代码(在多个位置),才能设置该新属性

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

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

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

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

    如果要保持成员常量,则无法实现移动操作。我建议反对康斯特议员

    谁有一个具有唯一ID的类的好例子


    std::unique_ptr
    本质上就是这样一个类的例子。“id”表示析构函数清理的某个唯一资源。

    如果每个对象都有一个唯一的、永久的标识,那么您可能无法真正支持复制——对象的副本应该与原始对象相同,在这种情况下,您说每个对象都应该是唯一的,因此拥有一个副本可能没有意义

    另一方面,搬迁建设应该更加合理。尽管ID从一个对象移动到另一个对象,但在给定的时间内,仍然只有一个对象具有给定的标识

    这个动作非常简单和直接。只需像往常一样在成员初始值设定项列表中初始化您的成员,包括这样一个事实,即由于它是一个移动向量,您希望从源中的唯一_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;
    }
    
    理论上,您可能应该在
    attribute1
    attribute2
    上使用
    std::move
    ,但由于它们是
    int
    s,所以通常不会产生任何实际的差异

    然后我们来讨论一个非常重要的问题:移动赋值。因为我们已经将
    唯一的\u id
    定义为
    常量
    ,所以我们不能仅仅复制它。要执行此任务,我们首先销毁目标对象的当前内容,然后使用placement new从源到目标执行移动构造:

    Example(Example&& other) 
      : unique_id(std::move(other.unique_id)) 
      , attribute1(other.attribute1)
      , attribute2(other.attribute2)  
    { 
    }
    
    这是因为
    const
    资格认证在破坏或施工期间无效,因此这基本上是我们执行任务的唯一方法

    下面是一个示例,演示了这一切:

    Example &operator=(Example&& other) { 
     this->~Example();
     new (this) Example(std::move(other));
     return *this;
    }
    
    #包括
    #包括
    #包括
    课例{
    公众:
    示例(const std::string&unique_id_uu、int attribute1_uu、int attribute2_uu):
    唯一标识(唯一标识)、属性1(属性1)、属性2(属性2){};
    无效集_attribute1(int attribute1_417;{attribute1=attribute1_417;
    无效集_attribute2(int attribute2_u2;){attribute2=attribute2_2;;}
    /*删除复制/移动/分配运算符以使每个实例唯一*/
    示例(const-Example&)=删除;
    示例和运算符=(示例和)=删除;
    示例(示例和其他)
    :unique_id(std::move(other.unique_id))
    ,attribute1(其他.attribute1)
    ,attribute2(其他.attribute2)
    { 
    }
    示例和运算符=(示例和其他){
    这个->~示例();
    新(此)示例(std::move(other));
    归还*这个;
    }
    私人:
    const std::字符串唯一\u id;
    int属性1;
    int属性2;
    
    friend std::ostream&operator这听起来像是一个.A
    std::unordered_map
    似乎是另一个选项,这样您就不需要
    示例中的任何
    unique_id
    内容了。对于类中显示的数据成员,您不需要显式重载移动构造函数或移动赋值操作符。DECL将它们声明为
    default
    。复制函数可以声明为
    delete
    ,以防止复制。我建议您少考虑类属性,多考虑行为。让所需的类成员由实现行为的需要决定。您的代码是否已经演示了如何完成#1?您提供了ded成员函数用于设置除
    唯一\u id
    之外的每个属性。这允许编辑除唯一id之外的所有属性。为什么这不足以实现您的真正目标?将您的唯一id和相关功能封装到一个专用类中,该类具有定制的构造函数、赋值运算符等以及访问器但没有设置程序(防止暴露ID数据以供外部代码修改)。然后,该类可以是基类,也可以是具有其他属性的类的成员。然后,编译器生成的复制/移动构造函数、赋值运算符等将根据需要进行操作。或者,如果需要,您可以将
    示例
    类设为单例。
    #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";
    }