3

A piece of code snippet:

std::unique_ptr<SDL_Renderer, decltype(&SDL_DestroyRenderer)>
cGraphics::Create_Renderer()
{
    SDL_Renderer* temprenderer = SDL_CreateRenderer(m_Window.get(), -1, 0);
    SDL_SetRenderDrawColor(temprenderer, 255, 255, 255, 0xff);
    return std::unique_ptr<SDL_Renderer,
                           decltype(&SDL_DestroyRenderer)>(temprenderer,
                                                           SDL_DestroyRenderer);
}

What I know:

  • temprenderer is of course destroyed when it goes out of scope;
  • a temporary std::unique_ptr is initialized with the raw pointer;
  • Although std::unique_ptr does not allow copy, it is OK to return by value;
  • Essentially the temporary std::unique_ptr is also destroyed when it goes out of scope;
  • We are now holding a copy of that temporary unique pointer

My question:

Why does the destruction of the raw pointer have no effect on the copy of the temporary unique pointer, which itself (the temporary unique pointer) is initialized with the raw pointer? In other words, what happens inside of that unique pointer that keeps the information from being lost?

My assumption is that the unique pointer also holds a raw pointer (e.g. .get()), and when it is initiated by temprenderer it copies the value of temprenderer onto the raw pointer, and that information is again copied when the unique pointer goes out of scope.

OK now it sounds quite obvious after I thought it through, but I'd appreciate if someone can confirm this. I also found this:

A unique_ptr explicitly prevents copying of its contained pointer (as would happen with normal assignment)

So maybe something extra happens when we return a unique_ptr?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
Nicholas Humphrey
  • 1,220
  • 1
  • 16
  • 33
  • 4
    The destruction of the raw pointer doesn't destruct the thing it points to. – tkausl Jun 21 '18 at 04:00
  • @tkausl Yes I know that. The only thing that is a bit puzzling is how that piece of information (the address of the object) passes from the raw pointer to the returned unique_ptr. Actually after I wrote everything out it seems to be much clearer. Just need a confirmation though. – Nicholas Humphrey Jun 21 '18 at 04:02
  • 2
    `The only thing that is a bit puzzling is how that piece of information (the address of the object) passes from the raw pointer to the returned unique_ptr.` The same way any other piece of information, for example an int, passes from caller to callee. – tkausl Jun 21 '18 at 04:03
  • 1
    i.e. it transfers ownership – Joseph D. Jun 21 '18 at 04:04

2 Answers2

1

When we return a temporary unique_ptr, the compiler actually "moves" the resources by calling move constructor. Once it has moved the resources, the original temporary unique_ptr goes out of scope and is destroyed. Even if the unique_ptr were a lvalue but if the compiler could figure out that it would anyway go out of scope (not needed anymore) after the function returns, it would perform copy elision and select the move constructor for returning.

Why does the destruction of the raw pointer have no effect on the copy of the temporary unique pointer, which itself (the temporary unique pointer) is initialized with the raw pointer? In other words, what happens inside of that unique pointer that keeps the information from being lost?

Because it's not the content that is being destroyed but the variable which holds the address. And once unique_ptr has the address of the content, why does it matter anyway?

My assumption is that the unique pointer also holds a raw pointer (e.g. .get()), and when it is initiated by temprenderer it copies the value of temprenderer onto the raw pointer, and that information is again copied when the unique pointer goes out of scope.

When a unique_ptr is initialized with temprenderer it simply copies the address pointed to by temprenderer into its own member variable. And that information is not copied but moved(transfer of ownership) when the control goes out of scope.

You might want to take a look at how unique_ptr is returned from a function

nishantsingh
  • 4,537
  • 5
  • 25
  • 51
  • Thanks for the reply! The first part definitely contains more knowledge than I can assume at the moment. I think the only thing I didn't get about your last paragraph is that I have been writing code for a while but never gave it a second thought. I'm going to read more about the move semantics. – Nicholas Humphrey Jun 21 '18 at 04:09
  • 1
    @NicholasHumphrey There you go http://thbecker.net/articles/rvalue_references/section_01.html – nishantsingh Jun 21 '18 at 04:10
1

A unique_ptr explicitly prevents copying of its contained pointer (as would happen with normal assignment)

template<class U, class E>
unique_ptr(unique_ptr<U, E>&& u) noexcept;

U is MoveConstructible and MoveAssignable, but is not CopyConstructible nor CopyAssignable as per unique.ptr/4.

Thus, it prevents copy. Instead it transfers ownership.

Joseph D.
  • 11,804
  • 3
  • 34
  • 67