2

It seems that initalizer lists are a good idea for your class constructors and, I'm assuming, for the copy constructor as well. For the assignment operator one has to assign each member in the body of the function. Consider the following simple block:

class Foo {
private: 
  int a,b;
public:
  Foo(int c, int d)  : a(c), b(d) {}
  Foo(const Foo & X) : a(X.a), b(X.b) {}
  Foo& operator=(const Foo& X) {
    if (this == &X) return *this;
    a = X.a;
    b = X.b;
    return *this;
  }
};

If a class has a moderate amount of data members, there are three places where one can mess up the the different assignments/initialization. By that I mean, what if the copy constructor looked like:

  Foo(const Foo & X) : a(X.a), b(X.a) {}

or a line was missing from the operator=. Since the assignment operator and the copy constructor often have the same effect (in that we copy members from one Foo to another) can I "reuse" the code from the copy constructor or the assignment operator or vice versa?

Community
  • 1
  • 1
Hooked
  • 84,485
  • 43
  • 192
  • 261
  • 3
    Getting right copy constructor and assignment operator is way more difficult than it seems; you should really read the [FAQ on the copy-and-swap idiom](http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom). On the other hand, as other said, in this case there's no need of user-declared copy constructors and assignment operators. – Matteo Italia Nov 08 '11 at 21:55
  • 2
    I usually use the operator= in the constructor: Foo(const Foo & X){ *this = X;} – Lucian Nov 08 '11 at 21:55
  • 1
    @freerider: in general that's not a good idea if your class manages resources that the `operator=` needs to free before copying. – Matteo Italia Nov 08 '11 at 21:56
  • 1
    @ matteo italia: I know, but I just answered the question in this example which does not contain heap allocations. Of course you should not use in more complicated classes. – Lucian Nov 08 '11 at 22:10

3 Answers3

11

Your goal should be to not write copy constructors/assignment operators at all. Your goal should be to let the compiler do it. Standard library containers are all copyable, so use them where reasonable.

If there are members that cannot be copied correctly, then use smart pointers or other RAII objects. Those objects are the ones that should need special copy constructors/assignments. And they only need them for their one member.

Everything else should not use them.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
  • constructors are common, to make lots of options. I agree with assignment though. – Mooing Duck Nov 08 '11 at 21:58
  • 1
    @MooingDuck: But _copy_ constructors can be left for the compiler to write (at least it should be safe if it is safe to let the compiler write the copy assignment operator). – CB Bailey Nov 08 '11 at 22:01
  • `... = default;` is your friend; use it. – Michael Price Nov 08 '11 at 22:05
  • @MooingDuck The compiler, even VC2010, will create a copy constructor and copy assignment operator for you whenever possible. The only times it won't are if you have members which do not have copy constructors/assignments. – Nicol Bolas Nov 08 '11 at 22:10
  • @MooingDuck: Why? Just let the compiler generated one do the right thing, you don't have to define it even if you do define other constructors. – CB Bailey Nov 08 '11 at 22:14
  • @NicolBolas: I believed that creating other constructors would cause the compiler to not create those, but a few quick tests show otherwise. My bad. Stick with the compiler generated versions. – Mooing Duck Nov 08 '11 at 22:17
4

Since the assignment operator and the copy constructor often have the same effect.

Not at all, one does initialization while the other does assignment. They are different in the initial state of the object, and their tasks are separate (though similar). The canonical assignment operator is usually done as:

Foo& operator=(Foo right) {
    right.swap( *this );
    return *this;
}
K-ballo
  • 80,396
  • 20
  • 159
  • 169
2

It might not be valid to forward all to an assignment operator, but that is was commmon in C++03 where it was allowed.

In C++11 constructors are easier: forward all the constructors to one master constructor.

class Foo {
private: 
  int a,b;
public:
  Foo(int c, int d)  : a(c), b(d) {}
  Foo(const Foo & X) : Foo(x.a, x.d) {} 
  //syntax may be wrong, I don't have a C++11 compiler
  Foo& operator=(const Foo& X) {
    if (this == &X) return *this;
    a = X.a;
    b = X.b;
    return *this;
  }
}

In C++03 (where it is allowed)

class Foo {
private: 
  int a,b;
  void init(int c, int d) {a=c; b=d;}
public:
  Foo(int c, int d)  : {init(c,d);}
  Foo(const Foo & X) : {init(X.a, X.b);} 
  Foo& operator=(const Foo& X) { init(X.a, X.b);} 
}

But keep in mind that this cannot be used in some common cases. (any object that isn't assignable)

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158