Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does my unique_ptr think is has a null function pointer deleter? [duplicate]

I'm trying to learn SDL using C++. I've created a window.h header and a window.cpp source file for storing a Window class. In window.h it looks something like this:

Class Window {
public:
  Window();
    . . .
private:
  std::unique_ptr<SDL_Window, void (*)(SDL_Window*)> window;
  std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer*)> renderer;
    . . .
}

with some of the code in the class omitted. Then, in my source file, in the definition of the default constructor, I do this:

Window::Window() {
  window = std::unique_ptr<SDL_Window, void (*)(SDL_Window*)>(nullptr, SDL_DestroyWindow);
  renderer = std::unique_ptr<SDL_Renderer, void (*)(SDL_Renderer*)>(nullptr, SDL_DestroyRenderer);
}

However, when I go to compile, I'm told that unique_ptr [is] constructed with null function pointer deleter, which as far as I can tell is false. Maybe I'm misunderstanding how to use a unique_ptr's deleter, but I cannot figure out what's wrong. Is there something I'm missing or have I completely misunderstood what I'm doing?

like image 430
abertsch Avatar asked Apr 07 '14 14:04

abertsch


2 Answers

The problem is that in your constructor, you use assignment instead of initialization for the members window and renderer. Your members are implicitly default initialized, which generates an error.

But why is this so and how to change it?

If you're new to C++ this might sound a bit strange, but any class member is initialized before the constructor function body is evaluated. Per default, each member will be initialized with its default constructor, or left uninitialized (if it's a primitive type like int). If you want to change this behavior (i.e. if you want to initialize it with something different, like you want), you have to use the member initializer list.

Example:

Window::Window() :   // <-- put a colon here
    windows(nullptr, SDL_DestroyWindow),     // here comes the member init list
    rendered(nullptr, SDL_DestroyRenderer)
{
}

Note: Since C++11, you can also initialize members at their definition directly (like you can do it in Java for example), but in your case this would make the header look too complex. Also, this wouldn't fit to the rule of encapsulation (in most cases, only the class implementation should know what to do with private members).

like image 200
leemes Avatar answered Sep 20 '22 04:09

leemes


Use a member initializer list:

Window::Window()
    : windows(nullptr, SDL_DestroyWindow), rendered(nullptr, SDL_DestroyRenderer)
{
    // empty
}

By the time the body of a constructor runs, all members shall already be initialized (default constructed unless you explicitly do something else, like above). Thereafter, you can only assign to them.

like image 24
jrok Avatar answered Sep 21 '22 04:09

jrok