I guess I over edited my first post so Ill try to make up for it here. I originally wanted to make a SDL encapsulation where I would store my window and GL Context into one class as well as any other information a game engine might need. I ended up getting errors so I reverse engineered them with this test class which has the stuff that my previous class had, but the constructors are more basic.
This code below, will make the test constructor call its destructor right after the constructor is called even though I never call the destructor explicitly. This happens if I pass to test the way I do here a premade string or if I just pass "" without setting it to a variable. In this case, it gives a access violation error because I try to destroy a not initialized window but the question is, why does the destructor get called if I never called it explicitly?
class test
{
private:
glm::vec2 screen;
GLuint VBO;
SDL_Window * win;
SDL_GLContext g;
public:
test (std::string Name,unsigned int screenx, unsigned int screeny);
test::test(std::string Name);
~test ();
};
test::test(std::string Name){}
test::~test ()
{
SDL_DestroyWindow(win);
win = nullptr;
}
int main (int argc, char * argv [])
{
// SDL Init
if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
{
printf( "SDL could not initialize! Error: %s\n", SDL_GetError() );
return 0;
}
std::string s = "";
test d = test(s);
On the other hand, if I change my constructor to this and I make the same call in main but without passing the string, the program runs just fine and the destructor isn't called.
test::test(){}
A more practical example is when I try to create the window, GL context, and make it a red screen with a white dot. Here's an example that works:
class test
{
private:
glm::vec2 screen;
GLuint VBO;
SDL_Window * win;
SDL_GLContext g;
public:
test (unsigned int screenx, unsigned int screeny);
~test ();
};
test::test (unsigned int screenx, unsigned int screeny) :
screen (glm::vec2(screenx, screeny)),
win (SDL_CreateWindow("",100,100,screen.x,screen.y,SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL)),
g (SDL_GL_CreateContext(win))
{
glewExperimental = GL_TRUE;
GLenum glewError = glewInit();
if ( glewError != GLEW_OK )
{
printf( "GameEngine: GLEW could not be initialized! Error: %s\n", glewGetErrorString(glewError) );
}
if ( win == nullptr )
{
return;
}
if ( g == NULL )
{
return;
}
SDL_GL_MakeCurrent(win, g);
GLfloat Vertex [3];
Vertex[0] = 0.0f;
Vertex[1] = 0.0f;
Vertex[2] = 0.0f;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex), Vertex, GL_STATIC_DRAW);
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0);
glBindBuffer( GL_ARRAY_BUFFER, VBO );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, 0 );
glDrawArrays(GL_POINTS, 0, 1);
glDisableVertexAttribArray(0);
SDL_GL_SwapWindow(win);
}
test::~test ()
{
SDL_DestroyWindow(win);
win = nullptr;
}
int main (int argc, char * argv [])
{
// SDL Init
if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
{
printf( "SDL could not initialize! Error: %s\n", SDL_GetError() );
return 0;
}
std::string s = "";
test i = test(100,100);
SDL_Delay(10000);
SDL_Quit();
return 1;
}
And here's one that calls the destructor right after the constructor is called. Notice the only difference is I pass a string as a parameter to the constructor but I don't actually do anything with this string. The program doesn't crash because the window is initialized but the window instantly gets destroyed instead.
class test
{
private:
glm::vec2 screen;
GLuint VBO;
SDL_Window * win;
SDL_GLContext g;
public:
test (std::string Name,unsigned int screenx, unsigned int screeny);
~test ();
};
test::test (std::string Name, unsigned int screenx, unsigned int screeny) :
screen (glm::vec2(screenx, screeny)),
win (SDL_CreateWindow("",100,100,screen.x,screen.y,SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL)),
g (SDL_GL_CreateContext(win))
{
glewExperimental = GL_TRUE;
GLenum glewError = glewInit();
if ( glewError != GLEW_OK )
{
printf( "GameEngine: GLEW could not be initialized! Error: %s\n", glewGetErrorString(glewError) );
}
if ( win == nullptr )
{
return;
}
if ( g == NULL )
{
return;
}
SDL_GL_MakeCurrent(win, g);
GLfloat Vertex [3];
Vertex[0] = 0.0f;
Vertex[1] = 0.0f;
Vertex[2] = 0.0f;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex), Vertex, GL_STATIC_DRAW);
glClearColor(1.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0);
glBindBuffer( GL_ARRAY_BUFFER, VBO );
glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, 0 );
glDrawArrays(GL_POINTS, 0, 1);
glDisableVertexAttribArray(0);
SDL_GL_SwapWindow(win);
}
test::~test ()
{
SDL_DestroyWindow(win);
win = nullptr;
}
int main (int argc, char * argv [])
{
// SDL Init
if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
{
printf( "SDL could not initialize! Error: %s\n", SDL_GetError() );
return 0;
}
std::string s = "";
test d = test(s, 100, 100);
SDL_Delay(10000);
SDL_Quit();
return 1;
}
All of these problems are solved if the string gets passed by reference but my question is, why is it that just by passing a string by value does my destructor automatically get called right after my constructor is called?
My second question is one that I sort of figured out why it crashes but not why it should crash. So here is an example that doesn't crash (assume that I call the constructor in main just as I have for the rest of my above code given the parameters and if I pass a string, its an empty string).
class test
{
private:
glm::vec2 screen;
GLuint VBO;
SDL_Window * win;
SDL_GLContext g;
std::string Name; // Added
public:
test (std::string _Name, unsigned int screenx, unsigned int screeny);
~test ();
};
test::test (std::string _Name, unsigned int screenx, unsigned int screeny) :
Name (_Name),
screen (glm::vec2(screenx, screeny)),
win (SDL_CreateWindow("",100,100,screen.x,screen.y,SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL)),
g (SDL_GL_CreateContext(win))
{
// The exact same code as the above constructor, make a red window with a white dot
}
This however, crashes giving access violation error at 0xcccccccc.
test::test (std::string _Name, unsigned int screenx, unsigned int screeny) :
Name (_Name),
screen (glm::vec2(screenx, screeny)),
win (SDL_CreateWindow(Name.c_str(),100,100,screen.x,screen.y,SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL)),
g (SDL_GL_CreateContext(win))
{
....
}
The only difference between this and the top is this part of the code:
win (SDL_CreateWindow(Name.c_str(), ...
In debug, I also get that Name is a <Bad Ptr> and I kinda figured out why. When I call Name (_Name) in the initialzier list, apparently it doesn't do the copying properly so instead, its actually a undefined variable. Then in SDL_CreateWindow, I'm trying to create a const char pointer to this memory which doesn't exist, therefore generating an exception. My question for this is, why is it that calling Name(_Name) doesn't actually copy over the strings value but instead, leaves it at undefined? As you can see as well, I'm initializing in the order of use so by the time win gets initialized, Name should be initialized as well. This works normally for g which creates a valid GL Context so I have to be going in the right order from top to bottom.
As a small note, I realize that passing a string by value isn't the best way to get things done but I'm interested in to knowing why these errors happen when I do so. I'm also doing this in the constructor because I feel that having an init method is pretty redundant if I just call it in the constructor anyways.