|
|
|
|
This is my little collection of C++ Tipps/Tricks/little known facts.
Every time i discover something worth adding, i will put it here. 1. Discovering Memory Leaks 2. CPUID/RDTSC 3. Exact Time Measuring 4. Functionpointer to class memberfunctions 5. Setting Fullscreen mode under windows 6. Know thy stringstreams 7. std::sort with non-static compare-method in a class 1. Discovering Memory Leaks Of course if you are working on a serious project you will use a sophisticated memory manager that will also discover memory leaks (along with their exact position in the code), but if you just want to do a quick test there is an easy way to let the debugger check for memory leaks: - Include crtdbg.h in your project. - At the beginning of you main() / WinMain () put this code:
int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG); flag |= _CRTDBG_LEAK_CHECK_DF; _CrtSetDbgFlag(flag); This works in VC++ ( i don't know about other compilers tho ) and, if you run the programm in debug mode (Hit F5), it will report memory leaks in the debug output window. 2. CPUID/RDTSC You have propably heard about the assembler instruction CPUID and RDTSC, which are supported by VC++ 6 and higher, but if you have an older compiler you can make use of the __emit function. This is a pseudo-asm instruction that lets you insert bytes directly into the outputted .exe. So, with a compiler that doesn't know the cpuid/rdtsc instuctions we can just use a little macro to put their respective opcodes directly as binary values into our program:
#define rdtsc __asm __emit 0fh __asm __emit 031h #define cpuid __asm __emit 0fh __asm __emit 0a2h 3. Exact time measuring If you want to measure something short, like the execution time of a function, or compute the framerate of your game as exact as possible, you have several ways to do this. One good way, esp. in a win32 app, is to use QueryPerformanceCounter. But with a little bit of assembler and the earlier mentioned RTDSC (Real Time Stamp Counter )instruction it is possible to get the current cpu cyclecount, so if we use the following before and after the execution of a function, we know how many clockcycles it needed. To do this we can use the following function:
__int64 GetCPUCount ( unsigned int loword, unsigned int hiword )
{
_asm
{
_emit 0x0f // insert rtdsc opcode
_emit 0x31
mov hiword , edx
mov loword , eax
}
return ( (__int64) hiword << 32 ) + loword;
}
Now we can get the number of clockcycles a function needs with something like unsigned int hi = 0, lo = 0; double t = GetCPUCount ( lo, hi ); But keep in mind that you can never have the EXACT cycle count the function used! After all we're working on a multitasking/multithreading OS, so it's not guaranteed that windows will not use some clockcycles up during the execution of our program. If you really want to get an exact count you can first set your program's priority level higher. Use SetPriorityClass ( HandleToOurProcess, REALTIME_PRIORITY_CLASS ); But be careful with that, windows might not like it and you won't be able to use the mouse as long as the prog runs or until the priority level gets set back to normal. 4. Functionpointer to class memberfunctions I think this little topic deserves a little space since it is almost impossible to find anything about it in the MSDN/compiler help files. (At least it took me really long to figure out how to do it :)) I assume that you know what function pointers are and how to use them (if not look it up in the MSDN :)), but it get's a little delicate when we come to member functions of classes. If we have a static function we have easy play: assume we have a static void myfunc( int ) in myclass. To declare a functionpointer to it and call it we do the follwing: typedef void ( *STATICFUNC ) ( int ); // declare function pointer STATICFUNC f = myclass::myfunc; // assign adress of memberfunction f ( 123 ); // call it But if you try this with a non-static member function you'll only get errors. Here's the way around it: (we assume same names as above, just non static ) typedef void ( myclass::*FUNC ) ( int );// note the asterisk AFTER myclass:: myclass obj; // instantiate myclass FUNC f = obj.myfunc; // assign adress ( obj.*f ) ( 123 ); // and call it It looks a bit weird ( like most C++ pointer operations) but it's the way how to do it. It is of course important to note that we always need an object to call the functionpointer. But the beauty is that this must not neccessarily be the original object, but it can be an instance of any class derived from myclass! Of course it's possible to live without those memberfunctionpointers, but they are a neat way to simplify things like an in-game console where now classes can register their nonstatic functions, which the console can then call when the user enters the corresponding command. 5. Setting Fullscreen mode under windows The following code changes screen resolution and sets windows that are created as WS_POPUP into fullscreen mode:
bool EnterFullscreen ()
{
DEVMODE newSettings;
// now fill the DEVMODE with standard settings, mainly monitor frequenzy
EnumDisplaySettings ( NULL, 0, &newSettings );
// set desired screen size/res
newSettings.dmPelsWidth = 800;
newSettings.dmPelsHeight = 600;
newSettings.dmBitsPerPel = 16;
//set those flags to let the next function know what we want to change
newSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
// and apply the new settings
if ( ChangeDisplaySettings ( &newSettings, CDS_FULLSCREEN )
!= DISP_CHANGE_SUCCESSFUL )
return false; // in case of error
else return true;
}
// and to reset the screen on program exit:
void ResetScreen ()
{
// this resets the screen to the registry-stored values
ChangeDisplaySettings ( NULL, 0 );
}
6. Know thy stringstreams Converting between numbers and number-strings (e.g. 123 and "123" ) is quite messy with old c functions like _itoa, atoi, atof etc. What many don't know: the STL presents us with a wonderful class that handles these operations in a typesafe and clean way, and, thanks to operator overloading, the code is the same for all standard number types (int, double, etc) : stringstreams! Here is some self-explanatory example program that converts between doubles and std::strings :
#include < sstream >
#include < iostream >
double fromstring ( std::string s )
{
double result;
std::stringstream str;
str << s;
str >> result;
return result;
}
std::string tostring ( double d )
{
std::string s;
std::stringstream str;
str << d;
str >> s;
return s;
}
void main ()
{
std::cout << tostring ( 123.456 ) << std::endl;
std::cout << fromstring("124") << std::endl;
}
Of course you can feed the fromstring function also char* instead of std::string without need to change the function itself since those will get automatically converted to std::string when the function is called.
If you really prefer to only use char* you just dochar* str = tostring(123).c_str()without the need to use std::strings directly 7. std::sort with non-static compare-method in a class Usually when you want to sort a std::vector or another container thats holds objects of a custom datatype you just write a function that takes two such objects, does something to find out if one is less than the other, and returns it. Then you pass the adress of this function to std::sort and voilá. But what when this functions relies outside data that is not global? It needs to be a class-member function. Consider this example:
class myclass
{
bool sortascending;
vector
when you try to compile this you will get an error, because there's no possible way to use a memberfunctionpointer as a normal functionpointer.So how to work around this restriction? For it to work we just use the fact that std::sort's 3rd parameter doesn't necessarily need to be a functionpointer, but can also be either the name of a class that implements an operator(), or, even better: an object of a class that implements operator() with the rightly-typed parameters. This means we can easily add a little struct to our class that will hold a pointer to myclass and can thus call the class-memberfunction in it's operator(), so that before sorting we only need to create an object of that struct, pass it a this-pointer and use this object in std::sort and everything works flawlessly:
class myclass
{
bool sortascending;
vector
|