Skip to content

Instantly share code, notes, and snippets.

@GoBigorGoHome
Last active February 23, 2019 05:13
Show Gist options
  • Select an option

  • Save GoBigorGoHome/e14954851d47c230ac49b3df1d15a2c9 to your computer and use it in GitHub Desktop.

Select an option

Save GoBigorGoHome/e14954851d47c230ac49b3df1d15a2c9 to your computer and use it in GitHub Desktop.
C++ notes

What "copying an object" actually means.

special member functions

copy constructor, copy assignment operator, and destructor are special member functions.

copy semantics (regarding to resource management)

the rule of three

copy elision

notes on move assignment operator

Consider the situation where a class manages a resource, such a class needs to implement The Big Three (because the default copy constructor and copy assignment operator do not work in this case).

Here we focus on copy constructor and copy assignment operator.

Can we also have a move assignment operator?

Yes, we do, but not always.

Consider the following code snippet:

class A {
  // this class has to manage a resource such as a manually allocated memeroy block
  A& operator= (A other) {
    swap(*this, other);
    return *this;
  }
  
  A& operator=(A &&other) {
    swap(*this, other);
    return *this;
  }
};

An rvalue of type A binds to both parameters equally well. So there is an overload ambiguity.

So this means if we implement the copy assignment operator mannully with the copy-and-swap idiom, then we cannot have a move assignment operator.

Actually, this is non-issue. If we have implemented the move constructor, then it's enough to add a copy assignment operator with its source argument passed by value (as the case of copy-and-swap idiom).

Let's demonstrate the idea in code.

class A {
  swap(A &a, A &b) {
  // swap function for copy-and-swap idiom
  }
  A(const A& other) {
    // a well-implemented copy constructor
  }
  A(A&& other) 
  : A() // initialize via default constructor, since C++11
  { 
    swap(*this, other);
  }
  A& operator=(A other) {
    swap(*this, other);
    return *this;
  }
};

A a;
b = expr_return_an_A;

Here is the analysis.

If expr_return_an_A returns an lvalue then the argument of A::operator= is copy constructed, if it returns an rvalue the argument is move constructed, and sometimes the move construction is hopefully elided. There is no significant overhead in either case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment