Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
219 views
in Technique[技术] by (71.8m points)

c++ - Why I'm getting "invalid use of incomplete type" error when I change raw pointer to unique_pointer?

I'm making some SDL2 wrappers in C++. Like this:

/* header file */
#include <SDL_mixer.h>
#include <memory>

class SDL2_Music {
 public:
  ~SDL2_Music() { free(); }
  bool loadMusic(const std::string& path);
  bool play(int loops = -1);
  // more methods
 private:
  void free();
  Mix_Music* music_ = nullptr;
};

/* cpp file */
void SDL2_Music::free() {
  if (music_ != nullptr) {
    Mix_FreeMusic(music_);
    music_ = nullptr;
  }
}
bool SDL2_Music::loadMusic(const std::string& path) {
  free();
  music_ = Mix_LoadMUS(path.c_str()); // this returns a Mix_Music*
  if (music_ == nullptr) {
    ktp::logSDLError("Mix_LoadMUS");
    return false;
  }
  return true;
}
// more stuff

This works fine, but I want to get rid of the raw pointer, so I can also get rid of the free() method and the dtor invoking it (yes, I'm reading about the rule of 0). So I made the following changes:

/* header file */
#include <SDL_mixer.h>
#include <memory>

class SDL2_Music {
 public:
  bool loadMusic(const std::string& path);
  bool play(int loops = -1);
  // more methods
 private:
  std::unique_ptr<Mix_Music> music_ = nullptr; 
};

/* cpp file */
bool SDL2_Music::loadMusic(const std::string& path) {
  music_ = std::make_unique<Mix_Music>(Mix_LoadMUS(path.c_str()));
  if (music_ == nullptr) {
    ktp::logSDLError("Mix_LoadMUS");
    return false;
  }
  return true;
}
// more stuff

When I try to compile (GCC) I get:

"C:Users ot_bjarneCodeBlocksMinGWlibgccx86_64-w64-mingw328.1.0includec++itsunique_ptr.h|831|error: invalid use of incomplete type 'struct _Mix_Music'"

And codeblocks points me to unique_ptr.h, which I obviously didn't tried to "fix".

question from:https://stackoverflow.com/questions/65942724/why-im-getting-invalid-use-of-incomplete-type-error-when-i-change-raw-pointer

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It seems that Mix_Music is an incomplete type and the correct way to free a Mix_Music object is to call the Mix_FreeMusic function. You cannot dispose of it the way you would a C++ object, namely by using delete. delete would attempt to call the destructor (which cannot be done in this context, since the type is incomplete here) and would assume that the object was allocated by new and return the memory to the same pool where new got it from. The way SDL allocates the object is an implementation detail, so you must let SDL deallocate the object itself as well, to ensure it is done properly.

std::unique_ptr can be used for this purpose, but requires a custom deleter. The default deleter will call delete, which should not be done here. The error you are seeing is because delete p; is ill-formed (where p has type Mix_Music*) because of the incompleteness. You must ensure that the custom deleter calls Mix_FreeMusic. You can see how to use custom deleters here: How do I use a custom deleter with a std::unique_ptr member?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...