c++ 具有常量成员的Swap方法

pjngdqdw  于 2023-02-26  发布在  其他
关注(0)|答案(7)|浏览(193)

我想为我的类(我们称之为A)实现一个Swap()方法,使copy-and-swap运算符=()。据我所知,swap方法应该通过交换类的所有成员来实现,例如:

class A 
{
  public:
    void swap(A& rhv) 
    {
        std::swap(x, rhv.x);
        std::swap(y, rhv.y);
        std::swap(z, rhv.z);
    }
  private:
    int x,y,z;
};

但是如果我有一个const成员,我应该怎么做呢?我不能调用std::swap来获得它,所以我不能编写A::Swap()。
编辑:实际上我的类更复杂一些。我想对它进行序列化和反序列化。常量成员是一段在这个对象中不会改变的数据(例如它的ID)。所以我想写这样的代码:

class A
{
  public:
    void Serialize(FILE* file) const
    {
        fwrite(&read_a, 1, sizeof(read_a), file);
    }

    void Deserialize(FILE* file) const
    {
        size_t read_a;
        fread(&read_a, 1, sizeof(read_a), file);
        A tmp(read_a);
        this->Swap(tmp);
    }

 private:
   const size_t a;
};

并调用这个代码:

A a;
FILE* f = fopen(...);
a.Deserialize(f);

很抱歉用了这么含糊的措辞。

pobjuy32

pobjuy321#

我认为你真正需要的是一个内部数据结构,你可以很容易地在对象之间交换。例如:

class A 
{
   private:

     struct A_Data {
       int x;
       int y;
       const int z;

       A_Data(int initial_z) : z(initial_z) {}
    };

    std::auto_ptr<A_Data> p_data;

  public:

     A(int initial_z) : p_data(new A_Data(initial_z)) {}

     void swap(A& rhv) {
        std::swap(p_data, rhv.p_data);
     }
};

这会使A对象内部数据的任何示例中的z值保持不变,但是您可以交换两个A对象的内部数据(包括常量z值),而不会违反常量正确性。

sirbozc5

sirbozc52#

在一夜好眠之后,我认为最好的答案是使用一个指向常量值的非常数指针--毕竟这些都是您要捕获的语义。

q43xntqr

q43xntqr3#

一个好的设计原则是把你的对象设计成不可变的。这意味着对象一旦创建就不能改变。要“改变”对象,你必须复制对象并确保改变你想要的元素。
也就是说,在这种情况下,您应该考虑使用复制构造函数来复制要交换的对象,然后实际交换对该对象的引用。我可以理解,仅仅能够在幕后更改对象的元素是很诱人的。但是最好是复制一个对象,然后用NEW对象替换对该对象的引用,这样可以避免任何常量的麻烦。
希望这个有用。

9lowa7mx

9lowa7mx4#

我建议您使用指向示例的指针。指针可以比classstruct中的数据更容易交换。

  • 交换 * 常量值的唯一方法是创建另一个对象,或者clone当前对象。

给定一个结构体:

struct My_Struct
{
  const unsigned int ID;
  std::string        name;
  My_Struct(unsigned int new_id)
    : ID(new_id)
  { ; }
};

我的理解是,您希望交换类似上面My_Struct的示例。您可以复制可变(非常数)成员,但不能复制const成员。更改const成员的唯一方法是为const成员创建一个新示例,并为该成员指定一个新值。
也许你需要重新考虑你的设计。

enyaitl3

enyaitl35#

恕我直言,你必须考虑不要交换CONST成员。
PD:我认为你可以考虑在你的方法中使用反射,这样你就不必维护函数了。

wz8daaqr

wz8daaqr6#

这就是为什么const_cast被创造出来的原因。只要记住不要把你的脚射掉。

**编辑:**好吧,我承认- const_cast根本不是为这个问题设计的。这可能对你的编译器有用,但你不能指望它,如果恶魔从你的鼻孔里飞出来,请不要责怪我。

ff29svar

ff29svar7#

tl;dr;:这是未定义的行为。
Reference/reason: CppCon 2017: Scott Schurr “Type Punning in C++17: Avoiding Pun-defined Behavior, @24m52s +- ”
举个例子,我的解释是:
假设你创建了一个T类型的对象,它有一些const成员。你可以把这个对象作为一个非常数引用传递给一个操作它的函数f(&T),但是你希望const成员在调用之后保持不变。swap可以在非常数引用中调用,并且它可以发生在函数f内部。打破了对呼叫者的const成员的前提。
使用swap的代码的每一部分都必须Assert被交换的T类型的对象不属于任何假定const成员为常量的上下文,这不可能自动验证 *。

  • 我只是假设这是不可能验证的,因为它看起来像是停机问题不可判定性的延伸。

相关问题