Copy constructor for a class with unique_ptr
Since the unique_ptr
can not be shared, you need to either deep-copy its content or convert the unique_ptr
to a shared_ptr
.
class A
{
std::unique_ptr< int > up_;
public:
A( int i ) : up_( new int( i ) ) {}
A( const A& a ) : up_( new int( *a.up_ ) ) {}
};
int main()
{
A a( 42 );
A b = a;
}
You can, as NPE mentioned, use a move-ctor instead of a copy-ctor but that would result in different semantics of your class. A move-ctor would need to make the member as moveable explicitly via std::move
:
A( A&& a ) : up_( std::move( a.up_ ) ) {}
Having a complete set of the necessary operators also leads to
A& operator=( const A& a )
{
up_.reset( new int( *a.up_ ) );
return *this,
}
A& operator=( A&& a )
{
up_ = std::move( a.up_ );
return *this,
}
If you want to use your class in a std::vector
, you basically have to decide if the vector shall be the unique owner of an object, in which case it would be sufficient to make the class moveable, but not copyable. If you leave out the copy-ctor and copy-assignment, the compiler will guide your way on how to use a std::vector with move-only types.
Copy constructor for a class with unique_ptr to an abstract class as a member
You did not say whether you have control of the code for the abstract class and the classes derived from it. If you do, then the easiest way is to provide a pure virtual method Clone
in the abstract class and implement it in derived classes. This method should handle creating the right copies. Unfortunately, because unique_ptr is not copyable you need to iterate through your vector and create copies by calling Clone
.
Copy constructor for a class that has unique ptr of a Base class
If you need to copy polymorphically, you will need to provide that in the interface of the type you are holding. Add a clone
virtual function to Base
and use that to create a copy that you can store in the copied Foo
.
Other alternatives include not copying (delete the copy constructor) or use reference semantics (copies refer to the same object: change unique_ptr
for shared_ptr
) but neither of those alternatives really provide copies.
Explicitly calling the copy constructor of an object inside unique_ptr
What I'd like to do is manually call the copy constructor of the
impl
class inside theunique_ptr
Here lies your error. As you are inside the (copy) constructor of potato
, there's no impl
object already constructed over which you'd have to "manually" invoke the copy constructor.
Just construct your new impl
passing to it a reference to the original impl
to copy.
potato::potato(const potato& p)
: _pimpl(std::make_unique<impl>(*p._pimpl) {
}
As for assignment, you can easily forward to the impl
assignment operator:
potato &operator=(const potato &p) {
*_pimpl = *p._pimpl;
return *this;
}
unique_ptr assignment and copy constructor clarification
In RegisterWindow
std::unique_ptr<Window> m_main_window; // for reference.
void Engine::registerWindow(Window &&window)
{
m_main_window = std::move(std::unique_ptr<Window>(&window)); // NOT CORRECT!
// crash waiting to happen!
}
std::unique_ptr<>
is a thin wrapper for pointers allocated with new. In other words delete m_main_window.get()
will be called from Engine's destructor. In addition, it is terrible practice to keep a pointer to a value passed by reference, as there is no guarantee that the window
object will live as long as Engine::m_main-window.
As pointed out by @Jarod42, you should consider receiving a std::unique_ptr as a parameter to RegisterWindow()
void Engine::registerWindow(std::unique_ptr<Window> wnd)
{
m_main_window = std::move(wnd);
}
// call as
std::unique_ptr<Window> w(new Window);
engine.registerWindow(std::move(w));
This ensures that the caller understands that wnd
must be allocated with new. And that Engine will take ownership of the pointer.
Unique_ptr in a class
Your copy constructor might look like
Human::Human(const Human& rhs) :
name_(rhs.name_),
cat_(rhs.cat_ ? std::make_unique<Cat>(*rhs.cat_) : std::nullptr)
{}
but getting rid of std::unique_ptr
and having Cat
by value (or std::optional<Cat>
) would be simpler:
Human::Human(const Human&) = default;
If Cat
is polymorphic, a clone
method would be required:
Human::Human(const Human& rhs) :
name_(rhs.name_),
animal_(rhs.animal_ ? rhs.animal_->clone() : std::nullptr)
{}
Why am I allowed to copy unique_ptr?
In the return statement, if you return a local variable, the expression is treated as an rvalue, and thus automatically moved. It is thus similar to:
return std::move(p);
It invokes the unique_ptr(unique_ptr&&)
constructor.
In the main function, bar()
produces a temporary, which is an rvalue, and is also properly moved into the p
in main
.
Related Topics
How Is Std::String Implemented
Where to Put Default Parameter Value in C++
How to Know the Exact Line of Code Where an Exception Has Been Caused
Throwing Exceptions from Constructors
Converting a Pointer into an Integer
Ull Suffix on a Numeric Literal
Const Int' Vs. 'Int Const' as Function Parameters in C++ and C
Why Doesn't a Derived Template Class Have Access to a Base Template Class' Identifiers
Strongly Typed Using and Typedef
Determining 32 VS 64 Bit in C++
How to Detect Win32 Process Creation/Termination in C++
Meaning of = Delete After Function Declaration
Using Strtok With a Std::String
Why Does Printf() Promote a Float to a Double
C++ Implicit Copy Constructor For a Class That Contains Other Objects