Search code examples
c++referencevariable-assignmentcopy-constructorassignment-operator

C++ reference can be assignable?


I've been messing with references wrapped in container classes. Why is the following code legal and appear to behave correctly?

#include <iostream>

class Foo
{
public:
  Foo( int i ) : i_( i ) {}
  int i_;
};

class FooWrapper
{
public:
  FooWrapper( Foo& foo ) : foo_( foo ) {}
  Foo& foo_;
};

int main( int argc, char* argv[] )
{
  Foo foo( 42 );
  FooWrapper fw( foo );
  FooWrapper fw2 = fw;
  std::cout << fw2.foo_.i_ << std::endl;
  return 0;
}

In the absence of an explicit operator=, I believe C++ does a memberwise copy. So when I do FooWrapper fw2 = fw;, is this not two operations: (1) create FooWrapper fw with a default ctor followed by (2) assignment from fw to fw2? I'm sure this isn't happening, because a reference can't be created uninitialized, so is the creation of fw2 actually treated as a copy construction?

I'm sometimes unclear on the roles of copy construction vs. assignment; they seem to bleed into each other sometimes, as in this example, but there's probably some rule I'm unaware of. I'd be grateful for an explanation.


Solution

  • In the line below, you are constructing fw2 by making it a copy of fw. That is, you are invoking the copy-constructor.

    FooWrapper fw2 = fw;
    

    Example

    Here is an (online) example on how default constructor, copy constructor, copy assignment operator, and move assignment operator (from C++11) are invoked.

    #include <iostream>
    
    struct foo
    {
        foo() {std::cout << "Default constructor" << '\n';}
        foo(foo const&) {std::cout << "Copy constructor" << '\n';}
        foo& operator=(foo const&) {std::cout << "Copy assignment operator" << '\n'; return *this; }
        foo& operator=(foo &&) {std::cout << "Move assignment operator" << '\n'; return *this; }
    };
    
    int main( int argc, char* argv[] )
    {
        foo a;            // Default constructor
        foo b = a;        // Copy constructor
        foo c;            // Default constructor
        c = b;            // Copy assignment operator
        b = std::move(c); // Move assignment operator
    }