skip to Main Content

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


  1. The constructor in your top example tries to copy the unique_ptr but a unique_ptr isn’t copyable.

    You need to move it instead:

    #include <utility>
    
    //...
    
    PtrOwner(std::unique_ptr<int>&& p) : p_(std::move(p)) {}
    

    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*:

    int& r = *p_;
    

    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 when r goes out of scope and be destroyed when the PtrOwner instance goes out of scope (or, if the ownership has been transferred, when the currently owning entity goes out of scope).

    Login or Signup to reply.
  2. What is good practice/accepted convention to pull this off?

    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, an std::vector, but without a copy constructor.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search