Rethipher
Rethipher

Reputation: 344

Class initialization list with struct pointer

I am looking at an example of the PIMPL idiom, and I found a line of code I really don't understand. Since I'm new to c++, and OOP, I was hoping somebody could explain what this function does.

Can somebody clarify this function?

PublicClass::PublicClass(const PublicClass& other)
    : d_ptr(new CheshireCat(*other.d_ptr)) { // <------- This line 
    // do nothing
}

/

Here is the example.

//header file:
class PublicClass {
public:
    PublicClass();                              // Constructor
    PublicClass(const PublicClass&);            // Copy constructor
    PublicClass(PublicClass&&);                 // Move constructor
    PublicClass& operator=(const PublicClass&); // Copy assignment operator
    ~PublicClass();                             // Destructor
    // Other operations...

private:
    struct CheshireCat;                         // Not defined here
    unique_ptr<CheshireCat> d_ptr;              // opaque pointer
};

/

//CPP file:
#include "PublicClass.h"

struct PublicClass::CheshireCat {
    int a;
    int b;
};

PublicClass::PublicClass()
    : d_ptr(new CheshireCat()) {
    // do nothing
}

PublicClass::PublicClass(const PublicClass& other)
    : d_ptr(new CheshireCat(*other.d_ptr)) {
    // do nothing
}

PublicClass::PublicClass(PublicClass&& other) 
{
    d_ptr = std::move(other.d_ptr);
}

PublicClass& PublicClass::operator=(const PublicClass &other) {
    *d_ptr = *other.d_ptr;
    return *this;
}

PublicClass::~PublicClass() {}

Upvotes: 0

Views: 642

Answers (3)

Ammar Husain
Ammar Husain

Reputation: 1849

C++ by default provides a copy constructor when the user does not define one: http://en.cppreference.com/w/cpp/language/copy_constructor

The line:

d_ptr(new CheshireCat(*other.d_ptr))

is simply dereferencing a pointer to an existing CheshireCat object and copying it to instantiate a new CheshireCat object that the d_ptr to the instantiated object points to.

Upvotes: 1

cdhowie
cdhowie

Reputation: 169143

The expression *other.d_ptr is parsed as equivalent to *(other.d_ptr). Let's take the syntax d_ptr(new CheshireCat(*other.d_ptr)) and work from the inside out to determine what it's doing:

  • other -- a PublicClass const & as declared.
  • other.d_ptr -- a unique_ptr<CheshireCat> const &, a reference to the d_ptr instance member of other.
  • *other.d_ptr -- the invocation of operator* on the unique_ptr object, which will yield a result of type CheshireCat const & (a reference to the object that the unique_ptr object owns).
  • new CheshireCat(*other.d_ptr) -- takes this CheshireCat const & and heap-allocates a new CheshireCat object by invoking the copy constructor of the CheshireCat type. This expression is of type CheshireCat *.
  • d_ptr(new CheshireCat(*other.d_ptr)) -- constructs the d_ptr member of the PublicClass object being constructed, using the CheshireCat * value. (This is the initializer list of this particular PublicClass constructor.)

In other words, all this line is doing is copying the CheshireCat object owned by the other instance, and giving ownership of that copy to the PublicClass object that is being constructed.

Upvotes: 1

Christian Hackl
Christian Hackl

Reputation: 27538

Structs do not "take values". Functions takes values. Constructors are functions. In new CheshireCat(*other.d_ptr), you invoke the compiler-generated copy constructor of CheshireCat.

You also do not pass a pointer but a reference, because you dereference other.d_ptr via the overloaded operator* of std::unique_ptr. In fact, if you wrote new CheshireCat(other.d_ptr) or new CheshireCat(other.d_ptr.get()), then you would get a compilation error.

Upvotes: 2

Related Questions