Swap method with const members

2019-04-27 22:59发布

问题:

I want to implement a Swap() method for my class (let's call it A) to make copy-and-swap operator=(). As far as I know, swap method should be implemented by swapping all members of the class, for example:

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

But what should I do if I have a const member? I can't call std::swap for it, so I can't code A::Swap().

EDIT: Actually my class is little bit more complicated. I want to Serialize and Deserialize it. Const member is a piece of data that won't change (its ID for example) within this object. So I was thinking of writing something like:

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

and call this code:

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

I'm sorry for such vague wording.

回答1:

After a good nights sleep I think the best answer is to use a a non-const pointer to a const value -- after all these are the semantics you are trying to capture.



回答2:

I think what you really want is to have an internal data structure that you can easily exchange between objects. For example:

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

This keeps the z value constant within any instance of A object internal data, but you can swap the internal data of two A objects (including the constant z value) without violating const-correctness.



回答3:

f0b0s, a good design principle is to design your objects to be immutable. This means that the object can't change once created. To "change" the object, you must copy the object and make sure to change the elements you want.

That being said, in this case you should look at using a copy constructor instead to copy the objects you want to swap, and then actually swap the references to the object. I can understand it'd be tempting just to be able to change the elements of an object under the hood, but it'd be better to make a copy of the object and replace the references to that object with the NEW object instead. This gets you around any const nastiness.

Hope this helps.



回答4:

I suggest you use pointers to the instances. The pointers can be swapped much easier than the data in the class or struct.

The only way to swap a constant value is to create another object, or clone the current object.

Given a struct:

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

My understanding is that you want to swap instances of something like My_Struct above. You can copy the mutable (non-const) members but not the const member. The only method to alter the const member is to create a new instance with a new value for the const member.

Perhaps you need to rethink your design.



回答5:

IMHO you must consider not to swap CONST members.

PD: I think you could consider to use reflection in your approach. so you don't have to maintain the function.



回答6:

This is why const_cast was created. Just remember not to shoot your foot off.

Edit: OK, I concede - const_cast wasn't made for this problem at all. This might work with your compiler, but you can't count on it and if demons come flying out of your nostrils, please don't blame me.



回答7:

tl;dr; : It's Undefined Behavior.

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

My interpretation, by example:

Suppose you create an object of type T, which have some const members. You can pass this object as a non-const reference to a function f(&T) that manipulates it, but you'd expect the const members to remain unalterable after the call. swap can be called in non-const references, and it can happen inside the function f, breaking the premise of const members to the caller.

Every part of your code that uses swap would have to assert that the object of type T being swapped does not belong to any context where the const members are assumed constant. That is impossible to automatically verify*.

*I just assumed that this is impossible to verify because it seems like an extension of the undecidability of the halting problem.



标签: c++ const swap