41

Is this a valid way to create an assignment operator with members that are references?

#include <new>

struct A
{
    int &ref;
    A(int &Ref) : ref(Ref) { }
    A(const A &second) : ref(second.ref) { }
    A &operator =(const A &second)
    {
        if(this == &second)
            return *this;
        this->~A();
        new(this) A(second);
        return *this;
    }
}

It seems to compile and run fine, but with c++ tendency to surface undefined behavior when least expected, and all the people that say its impossible, I think there is some gotcha I missed. Did I miss anything?

Daniel
  • 30,896
  • 18
  • 85
  • 139

4 Answers4

46

It's syntactically correct. If the placement new throws, however, you end up with an object you can't destruct. Not to mention the disaster if someone derives from your class. Just don't do it.

The solution is simple: if the class needs to support assignment, don't use any reference members. I have a lot of classes which take reference arguments, but store them as pointers, just so the class can support assignment. Something like:

struct A
{
    int* myRef;
    A( int& ref ) : myRef( &ref ) {}
    // ...
};
Christian Rau
  • 45,360
  • 10
  • 108
  • 185
James Kanze
  • 150,581
  • 18
  • 184
  • 329
10

Another solution is to use the reference_wrapper class ( in functional header ) :

struct A
{
    A(int& a) : a_(a) {}
    A(const A& a) : a_(a.a_) {}

    A& operator=(const A& a)
    {
        a_ = a.a_;
        return *this;
    }

    void inc() const
    {
        ++a_;
    }

    std::reference_wrapper<int>a_;

};
alangab
  • 849
  • 5
  • 20
  • With an assignment expression `a = b;` when `a` has type `reference_wrapper`, it seems that if `b` has type (convertible to?) `reference_wrapper`, this will *reseat* `a` to refer to `b`, but if not, and if `b` has type (convertible to?) `T`, the `T` object referenced by `a` will be assigned the value `b`. Is this true? If so, it seems to introduce some subtleties for implementing function templates that perform `a = b;` where we don't know the concrete types, but only that `b`'s type is implicitly convertible to `a`'s. – j_random_hacker Apr 19 '18 at 14:03
4

What you do its technically correct as far as I know, but it generates trouble. For instance, consider what happens with a derived class from A, since its assignment operator generates a new object (slicing). Can't you just turn the reference into a pointer within your class?

Besides that, copy constructors and assignment operators usually take its argument by const&.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
1

What you do is correct, but it is not very exception safe way of writing an copy assignment operator. Also, You should consider using a pointer member rather than an reference member.

You should implement it using the Copy and Swap Idiom. It has atleast 3 advantages over your implementation.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533