This question is a follow-up to Why doesn't returning a std::unique_ptr violate unique_ptr's deleted copy constructor? (which is answered here: Returning unique_ptr from functions )
This leads me back to the original problem I’d faced.
I have to work with a function (outside my control) that returns a std::unique_ptr
. I would like instances of a class to have a reference to the object the unique_ptr
encapsulates, but I’m unclear and fumbling with the syntax of what’s needed to pull this off.
I hope this sample code makes my intent clear, given that I can’t find the right model/syntax to make this compile: I’d like instances of class PtrOwner
to be able to "own" some form of reference to the underlying object encapsulated by the unique_ptr
that is returned by function getUniquePtr()
:
// main.cpp
#include <memory>
#include <iostream>
std::unique_ptr<int> getUniquePtr() {
return std::unique_ptr<int>(new int( 42 ));
}
class PtrOwner {
std::unique_ptr<int> p_;
public:
PtrOwner( std::unique_ptr<int> p ) : p_(p) {}
};
int main( int argc, char* argv[] ) {
PtrOwner po( getUniquePtr() );
return 0;
}
$ g++ --version && g++ -g ./main.cpp && ./a.out
g++ (Debian 6.3.0-18+deb9u1) 6.3.0 20170516
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
./main.cpp: In constructor ‘PtrOwner::PtrOwner(std::unique_ptr<int>)’:
./main.cpp:13:44: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’
PtrOwner( std::unique_ptr<int> p ) : p_(p) {}
^
In file included from /usr/include/c++/6/memory:81:0,
from ./main.cpp:2:
/usr/include/c++/6/bits/unique_ptr.h:359:7: note: declared here
unique_ptr(const unique_ptr&) = delete;
^~~~~~~~~~
What is good practice/accepted convention to pull this off?
I tried fumbling with the concept of PtrOwner
owning a shared_ptr
but I’m not adept with that class either, and couldn’t pull off the required syntax:
// main.cpp
#include <memory>
#include <iostream>
std::unique_ptr<int> getUniquePtr() {
return std::unique_ptr<int>(new int( 42 ));
}
class PtrOwner {
std::shared_ptr<int> p_;
public:
PtrOwner( const std::unique_ptr<int>& p ) : p_(p) {}
};
int main( int argc, char* argv[] ) {
PtrOwner po( getUniquePtr() );
return 0;
}
(I think the error from the second code block is too spammy for me to reasonably post here)
2
Answers
The constructor in your top example tries to copy the
unique_ptr
but aunique_ptr
isn’t copyable.You need to move it instead:
There’s nothing partial about the ownership though.
PtrOwner
is now the owner. Period.To get a reference to the underlying object, use
std::unique_ptr::operator*
:r
is here a reference to the underlying object and can be used to assign new values to the object (e.g.r = 10;
) but does not own it. The object will continue to exist whenr
goes out of scope and be destroyed when thePtrOwner
instance goes out of scope (or, if the ownership has been transferred, when the currently owning entity goes out of scope).Take @TedLyngmo’s suggestion. That is good practice. I’ll just offer some additional general intuition:
If your class holds a
std::unique_ptr
rather than a pointer – you can essentially forget about the use of the term "pointer" in there. Think of it as an opaque non-copyable object; you absolutely don’t have to worry about any heap storage. It’s a bit like, say, anstd::vector
, but without a copy constructor.