C++ Object Copying

Posted on July 14, 2016 by Richard Goulter
Tags: programming.c++

C++ is quite a different beast of a language to, say, Java or Python.
My early programming experience was in the latter, so I find my ‘mental model’ for reasoning about what C++ does with the code I write is sometimes wrong.

One area where I make mistakes is underestimating where C++ will make copies of objects.
That Java/Python are (largely) pass-by-reference, and C++ is pass-by-value (unless otherwise specified) is prob’ly what drives that. – Another way of saying this is that when “passing objects around”, Java/Python tend to only copy pointers to objects, whereas C++ (by default) usually makes copies of objects.

It may be helpful to illustrate this, to see where C++ copies things. (Or, perhaps it may be easier to remember where C++ doesn’t copy things).

Here’s one I prepared earlier. (The gist program contains a good output listing for the snippets below).

A Custom Object

Consider a custom object MyObj:

class MyObj {
 public:
     MyObj(int x) {
         cout << "    CONS MyObj(" << x << ")" << endl;
         x_ = x;
     }

     ~MyObj() {
         cout << "    DEST MyObj(" << x_ << ")" << endl;
     }

     MyObj(const MyObj& other) {
         x_ = other.x();
         cout << "    CPY  Copying from " << x_<< endl;
     }

     MyObj& operator=(const MyObj& rhs) {
         cout << "    ASSG Assigning from " << rhs.x() << " to " << x_ << endl;
         if (this == &rhs) return *this;

         x_ = rhs.x();

         return *this;
     }

     void setX(int x) { x_ = x; }

     int x() const { return x_; }

 private:
    int x_;
};

MyObj is a straightforward class; we provide a constructor, destructor, copy-constructor and assignment operator which each output when they’re called.

In Initialisation

  MyObj x0 = MyObj(10);  // A1
  MyObj x1(5);           // A2
  MyObj x2(x1);          // A3
  MyObj x3 = x1;         // A4

In Assignment

  x2 = x3;  // B1

In Function Calls

Consider functions:

void outp(MyObj o) {
    cout << "   Output MyObj(" << o.x() << ")" << endl;
}

void outpC(const MyObj& o) {
    cout << "   Output MyObj(" << o.x() << ")" << endl;
}

and the snippet:

  outp(x1);   // C1
  outpC(x1);  // C2

Assigning to References

  const MyObj& crx0 = x0;  // D1
  MyObj& rx0 = x0;         // D2

Assigning to references doesn’t invoke copies.

Results of Functions

Consider the function:

MyObj f1() {
    cout << "  f1():" << endl;
    return MyObj(7);
}

and the snippet:

  MyObj x4 = f1();          // E1
  const MyObj& crx4 = f1(); // E2
  MyObj& xr4 = f1();        // E3

both CONS no cpy, except 3 which doesn’t compile

Pointer Dereferencing

  MyObj* ptr = new MyObj(13);  // F1
  MyObj deref = *ptr;          // F2
  MyObj& derefRef = *ptr;      // F3
  const MyObj& constDeref = *ptr;  // F4
  delete ptr;                  // F5

Newer post Older post