1

I can't get clang (Apple LLVM version 4.2 (clang-425.0.28)) to compile these classes:

struct A {
    int f(){return 2;}
};
class Cl{
     std::unique_ptr<A> ptr;

public:
     Cl(){ptr = std::unique_ptr<A>(new A);}

     Cl(const Cl& x) : ptr(new A(*x.ptr)) { }
     Cl(Cl&& x) : ptr(std::move(x.ptr)) { }
     Cl(std::unique_ptr<A> p) : ptr(std::move(p))  { }

    void m_ptr(std::unique_ptr<A> p){
        ptr = std::unique_ptr<A>(std::move(p));
    }
    double run(){return ptr->f();}
};

I would like to run the constructor as follows:

std::unique_ptr<A> ptrB (new A);
Cl C = Cl(ptrB);

but if I do this I get the following compiler error: ../src/C++11-2.cpp:66:10: error: call to implicitly-deleted copy constructor of 'std::unique_ptr' C.m_ptr(ptrB);

I can solve the compiler problem by running Cl(std::move(ptrB)) but this doesn't actually move the ownership of A away from ptrB: I can still run ptrB->f() without causing a run-time crash... Secondly, the constructor is not very satisfying, since I want to hide the implementation of std::move in the class interface.

Thanks in advance.

Plamen
  • 650
  • 1
  • 8
  • 27

1 Answers1

2

Since ptrB is passed by value to Cl's copy constructor, a call to Cl(ptrB) tries to create a copy of ptrB which in turn calls a (obviously disabled) copy constructor of unique_ptr. In order to avoid creating an extra copy of ptrB, do the following:

Cl C = Cl(std::unique_ptr<A>(new A)); //A temporary is created on initialization, no extra copy steps performed

Or:

std::unique_ptr<A> ptrB (new A);
Cl C = Cl(std::move(ptrB)); //Move semantics used. Again, no extra copy steps

Or, use pass by reference (rvalue or lvalue) in your copy constructor:

class Cl{

//...
public:
//...
     Cl(std::unique_ptr<A> &p) : ptr(std::move(p))  { }

//...

};

std::unique_ptr<A> ptrB (new A);
Cl C = Cl(ptrB);

P.S Oh and by the way: the objects stay in unspecified, but valid state after std::move(). I believe that means you can still call ptrB->f(), and it is guaranteed to return 2 :)

AlexK
  • 1,279
  • 8
  • 19
  • Thanks! The pass by reference suits me best as I would like to keep the implementation of the class Cl out of the interface. Just one quick question before I mark the answer correct: with the pass by reference constructor, are there any copy steps or temporary objects being created? (I know you use move semantics, but it's new to me so I'm still asking stupid questions :) ) – Plamen Jul 19 '13 at 07:53
  • Nope. It's a classic pass by reference – AlexK Jul 19 '13 at 21:28