Reputation: 558
I'm writing toy C++ code to learn it and game dev, wrapping SDL along the way; all it does right now is load a BMP image and display it on the screen in a loop. Posting only relevant code.
EDIT: I'm revising this post down to the MVCE. The problem can be found much more directly.
#include <SDL.h>
#include <vector>
class Surface {
public:
Surface(SDL_Surface*);
~Surface();
SDL_Surface* mSurface;
}
Surface::Surface(SDL_Surface* surface) {
mSurface = surface;
}
Surface::~Surface() {
SDL_FreeSurface(mSurface);
}
int main(int argc, char* args[])
{
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
throw("Failed to SDL_Init: " + std::string(SDL_GetError()));
}
SDL_Window* window = SDL_CreateWindow("SDL TEST", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 1280, 960, SDL_WINDOW_SHOWN);
SDL_Surface* screenSurface = SDL_GetWindowSurface(window);
const char * imgPath = "test.bmp";
std::vector<Surface> surfaces;
surfaces.push_back(Surface(SDL_LoadBMP(imgPath)));
SDL_BlitSurface(surfaces.begin()->mSurface, // memory access violation here
NULL, screenSurface, NULL);
SDL_UpdateWindowSurface(window);
SDL_Delay(2000);
SDL_Quit();
return 0;
}
What it comes down to is that the pointer inside the Surface
object loaded into a vector
becomes invalidated. I read around and thought that maybe it had to do with needing a custom copy constructor, but making one like this didn't solve it:
Surface::Surface(const Surface& other) {
mSurface = other.mSurface;
mIsWindowSurface = other.mIsWindowSurface;
}
Upvotes: 1
Views: 253
Reputation: 141628
You didn't define a copy-constructor, so the default copy constructor is used and this doesn't do what you want.
In the line
surfaces.push_back(Surface(SDL_LoadBMP(imgPath)));
here is what happens:
Surface
whose mSurface
pointers to the newly allocated surfaceSurface
into the vector using the copy-constructor (or copy-assignment operator)Surface
, which calls SDL_FreeSurface
.Then when you go onto do surfaces.begin()->mSurface,
, you are trying to work with a surface that has already been freed.
To fix this prior to C++11 you will need to make your copy-constructor and copy-assignment operator semantically make a copy, or use a reference-count mechanism to ensure that SDL_FreeSurface
is only called once there are no more active pointers to the surface.
In C++11 there are a lot more out-of-the-box fixes; one of them is to disable copying for your class, and implement a move-constructor and move-assignment operator, and/or use emplace_back( SDL_LoadBMP
... instead of push_back
.
Upvotes: 1