[cpp] Some warnings and errors I can't fix

Started by
5 comments, last by scorpion007 16 years, 8 months ago
So I've been working on this little SDL framework, if you can even call it that, which will hopefully make my life a little easier when I'm making some simple games. At the moment I'm trying to get some sort of a state manager up and running. As the title says, I'm having difficulty fixing some warnings and errors. I know it's appreciated by most if I refrain from posting irrelevant code, but the truth is that I'm not quite sure what code is irrelevant. So I'll post the whole shebang. It's not _that_ much and I've done my best on the comments. States.txt
States are used to separate the global states a game can be in (say, the front-end menu, ingame, the help menu etc).

States are implemented by using three classes: StateBase, State and 
StateManager.
- StateBase is an abstract base class that provides functions for handling
events and logic and for rendering screens. The states will then inherit
from this class.
- State is a handle class that takes responsibility for handling the
complexity created by polymorphic use of states.
- StateManager manages a State stack. The idea of the State stack is that the
top element of the stack is the state that is in use (the so-called current
stack).
StateBase.h
#ifndef STATEBASE_H
#define STATEBASE_H

//Descr: The abstract base class of all the states.
/////////////////////////////////////////////////////////////////////


#include "SDL/SDL.h"

class StateBase {
	friend class State;
public:
	virtual ~StateBase();

	virtual bool HandleEvents() = 0;
	virtual bool HandleLogic() = 0;
	virtual bool RenderScreen(SDL_Surface*) = 0;

protected:
	// Clone() makes a copy of the object it is called from and returns
	// a pointer that points to that copy.
	virtual StateBase* Clone() const = 0;
};

#endif



State.h and State.cpp
#ifndef STATE_H
#define STATE_H

//Descr: State is a handle class for the classes that derive from
// the abstract base class Statebase. It's purpose is to hide the
// complexity caused by polymorphic use of the classes from the user.
/////////////////////////////////////////////////////////////////////

#include "StateBase.h"

// State ID's are unique labels that are given to states. Additional
// states that are created should have their own ID.
enum StateId { 
	STATE_NULL,  // Not an actual state. Used to communicate "no state".
	STATE_FEMENU, // The front-end menu state.
	STATE_INGAME // Ingame state. Should be sufficient for simple games.
};

class State {
public:
	// Needed constructors and assignment operator.
	State(StateId sid);
	State& operator=(const State& sc);
	~State() { delete s; }
	
	// All the work is simply forwarded to the state pointed to by s.
	bool HandleEvents()                  { return s->HandleEvents(); }
	bool HandleLogic()                   { return s->HandleLogic(); }
	bool RenderScreen(SDL_Surface* surf) { return s->RenderScreen(surf); }

private:
	// s points to an actual state.
	StateBase* s; 
};

#endif

#include "State.h"
#include "InGame.h"
#include <stdexcept>

using std::invalid_argument;

State::State(StateId sid)
{
	switch (sid) {
		/*case STATE_FEMENU:
			s = new FEMenu;
			break;*/
		case STATE_INGAME:
			s = new InGame;
			break;
		default:
			throw invalid_argument("The state ID is invalid.");
	}
}

State& State::operator=(const State& sc)
{
	// If the object isn't being assigned to itself
	if (&sc != this) {
		// delete the current state object pointed to 
		delete s;
		// and point to a clone of the other state object.
		s = sc.s->Clone();
	}
	return *this;
}



StateManager.h and StateManager.cpp
#ifndef STATEMANAGER_H
#define STATEMANAGER_H

//Descr: The statemanager manages a stack of states. It can change
//       states in three ways: by pushing a state on top of the
//       current state, by popping the current state on the stack and
//       by replacing the current state with a new one.
//Notes: The current state is always the top element of the stack.
/////////////////////////////////////////////////////////////////////

#include "State.h"
#include <stack>

class StateManager {
	// Type to describe methods of state changing.
	enum ChangeMethod {
		CM_NULL,
		CM_REPLACE,
		CM_PUSH,
		CM_POP
	};

public:
	// Initialize the implementation variables.
	StateManager(): nextStateId(STATE_NULL), isKilled(false), changeMethod(CM_NULL) { }

	// Set next state, which will replace the current state.
	bool NextStateReplace(StateId newState);
	// Set next state, which will be stacked on top of the current one.
	void NextStatePush(StateId newState);
	// Set next state to be the state under the current state in the stack,
	// deleting the current state in the process.
	bool NextStatePop();
	// Actually change to the next state, if there is one.
	bool ChangeState();

	// Returns a reference to the current state.
	State& CurrentState()  { return stateStack.top(); }

	// Kill the statemanager.
	void Kill() { isKilled = true; }
	// Check if the statemanager has been killed.
	bool IsKilled() { return isKilled; }

private:
	std::stack<State> stateStack;
	StateId nextStateId;
	bool isKilled;
	ChangeMethod changeMethod;	
};

#endif

#include "StateManager.h"

using std::stack;

bool StateManager::NextStateReplace(StateId newState)
{
	if(stateStack.empty() == false) {
		nextStateId = newState;
		changeMethod = CM_REPLACE;
		return true;
	} else
		return false;
}

void StateManager::NextStatePush(StateId newState)
{	
	nextStateId = newState;
	changeMethod = CM_PUSH;
}

bool StateManager::NextStatePop()
{
	if(stateStack.size() > stack<State>::size_type(1)) {
		changeMethod = CM_POP;
		return true;
	} else
		return false;
}

bool StateManager::ChangeState()
{
	switch(changeMethod) {
		case CM_NULL:
			return false;
		case CM_REPLACE:
			stateStack.top() = State(nextStateId);
			break;
		case CM_PUSH:
			stateStack.push(State(nextStateId));
			break;
		case CM_POP:
			stateStack.pop();
			break;
	}
	nextStateId = STATE_NULL; // RESET
	changeMethod = CM_NULL;   // RESET
	return true;
}



I've created a state called Ingame to test the framework: InGame.h and Ingame.cpp
#ifndef INGAME_H
#define INGAME_H

#include "StateBase.h"
#include "Button.h"

class InGame: public StateBase {
public:
	InGame()  { quit = new Button("quit.png", 20, 20); }
	~InGame() { delete quit; }

	bool HandleEvents();
	bool HandleLogic();
	bool RenderScreen(SDL_Surface*);

protected:
	InGame* Clone() const { return new InGame(*this); }

private:
	Button* quit;
};

#endif

#include "InGame.h"

bool InGame::HandleEvents()
{
	return true; // Not yet finished...
}

bool InGame::HandleLogic()
{
	return true; // Not yet finished...
}

bool InGame::RenderScreen(SDL_Surface *)
{
	return true; // Not yet finished...
}



I'm getting the following output:
Quote:Compiling... main.cpp SDLVideo.cpp Ingame.cpp c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const' with [ _Elem=char, _Traits=std::char_traits, _InIt=std::istreambuf_iterator> ] c:\program files\microsoft visual studio 8\vc\include\xlocnum(1365) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled with [ _Elem=char, _InIt=std::istreambuf_iterator> ] c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const' with [ _Elem=wchar_t, _Traits=std::char_traits, _InIt=std::istreambuf_iterator> ] c:\program files\microsoft visual studio 8\vc\include\xlocnum(1371) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled with [ _Elem=wchar_t, _InIt=std::istreambuf_iterator> ] State.cpp c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const' with [ _Elem=char, _Traits=std::char_traits, _InIt=std::istreambuf_iterator> ] c:\program files\microsoft visual studio 8\vc\include\xlocnum(1365) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled with [ _Elem=char, _InIt=std::istreambuf_iterator> ] c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const' with [ _Elem=wchar_t, _Traits=std::char_traits, _InIt=std::istreambuf_iterator> ] c:\program files\microsoft visual studio 8\vc\include\xlocnum(1371) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled with [ _Elem=wchar_t, _InIt=std::istreambuf_iterator> ] StateManager.cpp Button.cpp c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const' with [ _Elem=char, _Traits=std::char_traits, _InIt=std::istreambuf_iterator> ] c:\program files\microsoft visual studio 8\vc\include\xlocnum(1365) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled with [ _Elem=char, _InIt=std::istreambuf_iterator> ] c:\program files\microsoft visual studio 8\vc\include\xlocnum(590) : warning C4312: 'type cast' : conversion from 'uintptr_t' to 'void *' of greater size c:\program files\microsoft visual studio 8\vc\include\xlocnum(566) : while compiling class template member function 'std::istreambuf_iterator<_Elem,_Traits> std::num_get<_Elem,_InIt>::do_get(_InIt,_InIt,std::ios_base &,std::ios_base::iostate &,void *&) const' with [ _Elem=wchar_t, _Traits=std::char_traits, _InIt=std::istreambuf_iterator> ] c:\program files\microsoft visual studio 8\vc\include\xlocnum(1371) : see reference to class template instantiation 'std::num_get<_Elem,_InIt>' being compiled with [ _Elem=wchar_t, _InIt=std::istreambuf_iterator> ] Generating Code... Compiling manifest to resources... Linking... !!!FIXEDState.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall StateBase::~StateBase(void)" (??1StateBase@@UAE@XZ) referenced in function __unwindfunclet$??0InGame@@QAE@XZ$0 FIXED!!! StateManager.obj : error LNK2019: unresolved external symbol __imp___CrtDbgReportW referenced in function "public: class State const & __thiscall std::_Deque_const_iterator,1>::operator*(void)const " (??D?$_Deque_const_iterator@VState@@V?$allocator@VState@@@std@@$00@std@@QBEABVState@@XZ) C:\Projects\Application\Debug\Application.exe : fatal error LNK1120: 2 unresolved externals
Yikes! If anyone could shed some light on the matter, that would be great. On a different note, if you happen to read the code and you believe It's a bad design or you think it's bad in some other way, I'd love to hear from you. I'm always trying to improve, so I welcome all constructive criticism. [Edited by - atRoot on August 4, 2007 4:26:45 PM]
Advertisement
One quick observation: it looks like ~StateBase() is declared, but not defined. Try changing:
virtual ~StateBase();
To:
virtual ~StateBase() {}
There are obviously some other things going on as well, but this might clear up one of your errors.

One other note - other design issues aside, using 'smart' rather than 'raw' pointers throughout will get rid of some of the manual memory management you have in place currently (which in turn will make your code cleaner, clearer, and less error-prone).
You clearly have a template error. The bad news is that with templates commenting out a few lines at a time is the most effective way to debug.

You can also look into a tool that can translate those damn template errors into "english"
Quote:Original post by jyk
One quick observation: it looks like ~StateBase() is declared, but not defined. Try changing:
virtual ~StateBase();
To:
virtual ~StateBase() {}
There are obviously some other things going on as well, but this might clear up one of your errors.

Alright. That takes care of the first linker error.

Quote:Original post by jyk
One other note - other design issues aside, using 'smart' rather than 'raw' pointers throughout will get rid of some of the manual memory management you have in place currently (which in turn will make your code cleaner, clearer, and less error-prone).

I haven't really looked into smart pointers yet. I didn't realize they apply to these situations. I'll make sure I look into it. Thanks for the advice :)

Quote:Original post by fpsgamer
You clearly have a template error. The bad news is that with templates often commenting out a few lines at a time is the most effective way to debug.

You can also look into a tool that can translate those damn template errors into "english"

I clearly have. And I truly am baffled by the warnings. When I first encoutered it I figured it was caused by
if(stateStack.size() > stack<State>::size_type(1)) (in StateManager::NextStatePop() )
which was
if(stateStack.size() > 1)
at the time.
The warnings were gone. But when replaced "stack<State>::size_type(1))" with "1" again to test something, replacing it with "stack<State>::size_type(1))" had no effect anymore. The warnings just kept appearing.
I now figure it must be something else, even though I don't know what. I appear to make an implicit conversion somewhere, but I can can't find it, even though I use templates in a very limited fashion (the stack).

I actually have tried to use the STL Error Message Decryptor, but I can't get it to work yet. Thanks for the hint, though.
Well, I've located the line that's causing the second linker error:
stateStack.top() = State(nextStateId); (in StateManager::ChangeState() )
I'm still not sure why it is causing an error, though.
atRoot, I believe the warnings are caused by SDL, and the /MD compiler flag.

Please check your project settings and tell me if that is the case (/MD).

Changing it to /MT and /MTd for release/debug builds respectively seems to eliminate those warnings.

I'm not actually sure about the real reason the warnings are happening, so I'd be happy to hear an explanation.

Thanks

EDIT: Actually, scratch that, using /MT won't even link.

EDIT2: Ah, I found a fairly simple way around the problem: #include <SDL.h> *after* <iostream> or other C++ headers (in your case it looks like <stack>). That should eliminate the warnings too.

I still don't know the exact cause though...

[Edited by - scorpion007 on August 16, 2007 10:10:13 PM]

This topic is closed to new replies.

Advertisement