使用const成员的交换方法

时间:2010-02-05 21:01:15

标签: c++ const swap

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

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()。

编辑:其实我的课程有点复杂。我想序列化和反序列化它。 Const成员是一个不会在此对象中更改(例如其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);

对于这种模糊的措辞,我很抱歉。

7 个答案:

答案 0 :(得分:8)

我认为您真正想要的是拥有一个可以在对象之间轻松交换的内部数据结构。例如:

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);
     }
};

这使z值在A对象内部数据的任何实例中保持不变,但您可以交换两个A对象的内部数据(包括常量z价值)而不违反常识。

答案 1 :(得分:4)

经过一夜好眠后,我认为最好的答案是使用一个指向const值的非const指针 - 所有这些都是你想要捕获的语义。

答案 2 :(得分:3)

f0b0s,一个好的设计原则是将你的对象设计为不可变。这意味着一旦创建对象就无法更改。要“更改”对象,必须复制对象并确保更改所需的元素。

话虽如此,在这种情况下,你应该看一下使用复制构造函数来复制你想要交换的对象,然后实际交换对象的引用。我可以理解,只是能够改变对象下的对象元素是诱人的,但是最好制作对象的副本并用 NEW <替换对该对象的引用/ strong>对象而不是。这可以让你了解任何常识。

希望这有帮助。

答案 3 :(得分:1)

我建议你使用指向实例的指针。指针可以比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成员的新值创建新实例。

也许您需要重新考虑您的设计。

答案 4 :(得分:0)

这就是创建const_cast的原因。记住不要甩开你的脚。

编辑:好的,我承认 - const_cast根本就没有针对这个问题。这可能适用于你的编译器,但你不能指望它,如果恶魔飞出你的鼻孔,请不要怪我。

答案 5 :(得分:0)

恕我直言,你必须考虑不要交换CONST成员。

PD:我认为你可以考虑在你的方法中使用反射。所以你不必维护这个功能。

答案 6 :(得分:0)

TL;博士; :这是未定义的行为。

Reference/reason: CppCon 2017: Scott Schurr “Type Punning in C++17: Avoiding Pun-defined Behavior, @24m52s +- ”

我的解释,例如:

假设您创建了一个T类型的对象,该对象包含一些const个成员。您可以将此对象作为非const引用传递给操作它的函数f(&T),但是您希望const成员在调用后保持不变。 swap可以在非const引用中调用,它可以在函数f内部发生,从而打破了const成员对调用者的前提。

使用swap的代码的每个部分都必须声明被交换的类型T的对象不属于假定const成员不变的任何上下文。这是不可能自动验证*。

*我只是假设这是不可能验证的,因为它似乎是停止问题不可判定性的延伸。