• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
sasho648

My first public solution

25 posts in this topic

So this actually is my first solution I made [img]http://public.gamedev.net//public/style_emoticons/default/tongue.png[/img] . It is c++ new\delete memory leaks finder. It does an memory check at the end of the program and if some object created with new wasn't deleted it post a message with the object line and source file name. It use an a tree for collecting runtime memory actions. Here is the .cpp and .h file. I will be happy for any opinion and advice about this solution.

MemoryHandler.cpp

[source]#include <iostream>
#include <windows.h>
#include <stdio.h>

#ifdef DEBUG
struct MemoryAllocTree {
char* File;
unsigned int Line;
MemoryAllocTree* next;
void* MemoryPointer;
} * _gpAllocTree(0) ;
MemoryAllocTree** ppCurAllocTree(&_gpAllocTree);
unsigned int _gCurLine;
char* _gCurFile;
#endif

void* operator new(size_t size)
{
void* pMem(malloc(size ? size : 1));
if(!pMem)
{
#ifdef WIN32_MEM_LOG
MessageBoxA(0, "No more memory to use. The app will exit now!", "Error!", MB_OK | MB_ICONERROR);
#endif
#ifndef WIN32_MEM_LOG
std::cout << "No more memory to use. The app will exit now!" << "Error!" << std::endl;
#endif
exit(1);
}
#ifdef DEBUG
(*ppCurAllocTree)=(MemoryAllocTree*)malloc(sizeof(MemoryAllocTree));
if(!(*ppCurAllocTree))
{
#ifdef WIN32_MEM_LOG
MessageBoxA(0, "No more memory to use for the debug version of MemoryHandler. Try compiling the app \
in release mode. It will exit now!", "Error!", MB_OK | MB_ICONERROR);
#endif
#ifndef WIN32_MEM_LOG
std::cout << "No more memory to use for the debug version of MemoryHandler. Try compiling the app \
in release mode. It will exit now!" << "Error!" << std::endl;
#endif
exit(1);
}
(*ppCurAllocTree)->Line=_gCurLine;
(*ppCurAllocTree)->File=_gCurFile;
(*ppCurAllocTree)->MemoryPointer=pMem;
(*ppCurAllocTree)->next=0;
ppCurAllocTree=&(*ppCurAllocTree)->next;
#endif
return pMem;
}

void* operator new[](size_t size)
{
return operator new(size);
}

void operator delete[](void* pMem)
{
operator delete(pMem);
}

void operator delete(void* pMem)
{
if(!pMem) return;
#ifdef DEBUG
MemoryAllocTree* sourc(_gpAllocTree);
while(sourc&&sourc->MemoryPointer!=pMem)
sourc=sourc->next;
if(!sourc)
{
#ifdef DEBUG
#ifdef WIN32_MEM_LOG
char str[80];
sprintf(str, "Invalid delete call at File: %s Line: %d", _gCurFile,
_gCurLine);
MessageBoxA(0, str, "Warning!", MB_OK | MB_ICONWARNING);
#endif
#ifndef WIN32_MEM_LOG
std::cout << "Invalid delete call at File: " << _gCurFile << " Line: " << _gCurLine << " Warning!" << std::endl;
#endif
#endif
return;
}
sourc->MemoryPointer=0;
#endif
free(pMem);
return;
}

#ifdef DEBUG
void EndOfProgramMemCheck() {
MemoryAllocTree* pCurAllocTree(_gpAllocTree);
while(pCurAllocTree) {
if(pCurAllocTree->MemoryPointer) {
#ifndef WIN32_MEM_LOG
std::cout << "Object at line: " << pCurAllocTree->Line << " in file: "
<< pCurAllocTree->File << " wasn't deleted!" << std::endl;
#endif
#ifdef WIN32_MEM_LOG
char str[80];
sprintf(str, "Object at line: %d in file: %s wasn't deleted!", pCurAllocTree->Line,
pCurAllocTree->File);
MessageBoxA(0, str, "Memory leaked!", MB_OK | MB_ICONWARNING);
#endif
}
MemoryAllocTree* cach(pCurAllocTree);
pCurAllocTree=pCurAllocTree->next;
free(cach);
}
}
#endif[/source]


MemoryHandler.h

[source]#pragma once

/*Sasho 648 Memory Handle functions and memory leaks finder
- define DEBUG to active it and add at the function EndOfProgramMemCheck()
before exit your app. Define a WIN32_MEM_LOG to active an Win32 Messages.
Type MEM_FUNC_CALL at the line begin where new\delete \[] function is called.
Example: MEM_FUNC_CALL char* ptr = new char[50];
*/

#ifdef DEBUG
extern unsigned int _gCurLine;
extern char* _gCurFile;
#endif

#ifdef DEBUG
#define MEM_FUNC_CALL _gCurLine=__LINE__; _gCurFile=(char*)__FILE__;
#endif

#ifndef DEBUG
#define MEM_FUNC_CALL
#endif

void* operator new(size_t size) ;
void* operator new[](size_t size) ;
void operator delete[](void* pMem) ;
void operator delete(void* pMem) ;

#ifdef DEBUG
void EndOfProgramMemCheck() ;
#endif
[/source]


You need to make compiling debug define (DEBUG) at the compiler options and for win32 message posting you need to define WIN32_MEM_LOG. Before each new\delete call you need to type MEM_FUNC_CALL.

Here is a simple code using my solution:

[source]class My {
public:
My() {std::cout<<"My::My()"<<std::endl;}
~My() {std::cout<<"My::~My()"<<std::endl;}
} ;

int main() {
MEM_FUNC_CALL My* ptr=new My[23];
MEM_FUNC_CALL delete[] ptr;
MEM_FUNC_CALL delete ptr;
size_t* My_Size_T=new size_t;
My_Size_T=(size_t*)0xbff7ffff;
delete My_Size_T;
#ifdef DEBUG
EndOfProgramMemCheck();
#endif
system("PAUSE");

return 0;
}[/source]


Here will print warning messages for invalid delete call (2) and a memory leak. Edited by sasho648
0

Share this post


Link to post
Share on other sites
[font=trebuchet ms,helvetica,sans-serif]Funny how i just read about comments and the next program i see hasnt got any[img]http://public.gamedev.net//public/style_emoticons/default/biggrin.png[/img][/font][font=trebuchet ms,helvetica,sans-serif] [img]http://public.gamedev.net//public/style_emoticons/default/biggrin.png[/img][/font][font=trebuchet ms,helvetica,sans-serif] i skimmed over i tbut i cant understand whats going on exactly(not because of the comments!) because im still going through the c++ documentation.[/font]
0

Share this post


Link to post
Share on other sites
[quote name='sasho648' timestamp='1347299520' post='4978639'][code]extern unsigned int _gCurLine;
extern char* _gCurFile;[/code][/quote][quote][code]#define MEM_FUNC_CALL _gCurLine=__LINE__; _gCurFile=(char*)__FILE__;[/code][/quote]

[URL=http://imageshack.us/photo/my-images/405/skijl.png/][IMG]http://img405.imageshack.us/img405/4421/skijl.png[/IMG][/URL]

For instance, try the following code:
[code]
#include "MemoryHandler.h"
#include <iostream>

class A { };

class B {
public:
B() { MEM_FUNC_CALL a = new A(); }
~B() { MEM_FUNC_CALL delete a; }

private:
B( const B& );
B& operator= ( const B& );

private:
A* a;
};

int main( int, char*[] ) {
B* b = 0;
if ( false )
MEM_FUNC_CALL b = new B;

EndOfProgramMemCheck();
}
[/code]

You can also [url="http://blogs.msdn.com/b/calvin_hsia/archive/2009/01/19/9341632.aspx"]override new and new[][/url] to include additional parameters and use a macro to hijack all calls to new and delete to call your overloaded version, without needing to remember to use MEM_FUNC_CALL. (Though, you do need to make sure that the macros are defined in each compilation unit.) Take a look at a demonstration of [url="http://msdn.microsoft.com/en-us/library/x98tx3cf%28v=vs.100%29.aspx"]memory leak detection[/url] for Visual Studio on MSDN. It should give you some ideas.

Also:
Those aren't trees, those are linked lists :| Edited by fastcall22
2

Share this post


Link to post
Share on other sites
[list]
[*]Identifiers starting with an underscore in the global scope are reserved for the implementation, so I wouldn't prefix globals with "_". Namespaces are your friend.
[*]<stdio.h> is a C header. The C++ equivalent is <cstdio>. I'm actually not entirely sure why you include it.
[*]You should be reporting errors to std::cerr, not std::cout.
[*]Don't exit() when an allocation fails. Let the user determine if it's fatal. Throw a std::bad_alloc exception, like the normal new operator does.
[*]Any planned future support for multithreading (it'll wreck havoc with your current global state)?
[*]It would be useful if it didn't call any Windows specific functions so that it would be cross platform. Maybe output results/leaks to a log file?
[/list]

Overall, it's a cool idea, and I think with some changes suggested by fastcall22 and me (and others who contribute), it could be a cool little project. Edited by Cornstalks
1

Share this post


Link to post
Share on other sites
[quote name='sasho648' timestamp='1347299520' post='4978639'][source]MessageBoxA(0, str, "Memory leaked!", MB_OK | MB_ICONWARNING);[/source][/quote]

You make this call multiple times. Don't. Just use 'MessageBox'. The reason that there's a macro defining the name is for character width (I think).
-1

Share this post


Link to post
Share on other sites
[quote name='BinaryPhysics' timestamp='1347451873' post='4979274']
[quote name='sasho648' timestamp='1347299520' post='4978639'][source]MessageBoxA(0, str, "Memory leaked!", MB_OK | MB_ICONWARNING);[/source][/quote]

You make this call multiple times. Don't. Just use 'MessageBox'. The reason that there's a macro defining the name is for character width (I think).
[/quote]
MessageBoxA is [i]technically[/i] the correct function to call for narrow width strings, which is what he has. If you use MessageBox you also have to, perhaps unnecessarily for cases like this, decorate the string to ensure that the string is actually compatible with the function that the macro expands to.

Not saying one or the other is better, just that the macro needs more support code, or unnecessary support code depending on your point of view, to function properly.
0

Share this post


Link to post
Share on other sites
Thanks for the advices!
@fastcall22 I try adding the new operator additional parameters but it have ambigouos meaning. Here is what I mean:
[source lang="cpp"]void* operator new(size_t size, const char* szFile=__FILE__, unsigned int nLineNo=__LINE__) _GLIBCXX_THROW (std::bad_alloc)
__attribute__((__externally_visible__));[/source]

The error message is for the ambigouos function meaning (void* operator new(std::size_t) is the other). I tried using namespace to fix this but I think this is impossible.
0

Share this post


Link to post
Share on other sites
Actually, your new operator is amibouos because of the default parameters. It now has the same signature as the regular new operator (the first parameter is filled by the compiler). Leave out the default parameters and you'll be fine. Then use macros (yeah, I know... bad time ;) ) to replace all occurences of new with your version:
[CODE]
void* operator new(size_t size, const char* szFile, unsigned int nLineNo);
#define MY_NEW new(__FILE__, __LINE__)
#define new MY_NEW
[/CODE] Edited by brx
0

Share this post


Link to post
Share on other sites
Yeah I do this and fix the problem minutes ago (forgoting to edit the post) but the problem now is that I can't find I way to do the same with the delete operator:
[CODE]
#define delete delete ( __FILE__ , __LINE__ ) //for my own delete function
//void operator delete(void* pMem, const char* szFile, unsigned int nLineNo)
[/CODE]

This define doesn't work. I need the line and file for this function because it will output an error when you wrong call the function.
0

Share this post


Link to post
Share on other sites
[quote name='RulerOfNothing' timestamp='1348153153' post='4982051']
You need to get rid of the space between delete and (.
[/quote]

This doesn't work for me. Can you give me an example code or explaining me more clearly. Edited by sasho648
0

Share this post


Link to post
Share on other sites
Just a shot in the dark, but it's possible that the macro is expanding indefinitely, since the macro definition contains a reference to itself. It may be why [url=http://msdn.microsoft.com/en-us/library/x98tx3cf%28v=vs.100%29.aspx]memory leak detection in Visual Studio[/url] uses two macros instead of the one:

[code]
#define DBG_NEW new ( _NORMAL_BLOCK, __FILE__, __LINE__ )
#define new DBG_NEW
[/code]

So your delete may look something like:
[code]
#define DBG_DELETE delete ( __FILE__, __LINE__ )
#define delete DBG_DELETE
[/code]
0

Share this post


Link to post
Share on other sites
I believe that you can overload the delete operator to take additional parameters but it cannot be called except for one particular situation: when the constructor fails for an object allocated with a new taking multiple parameters, the corresponding delete with multiple parameters are called. Otherwise, a delete with custom parameter cannot be called.

Thus, if you overload delete like you do, the only way to have it called is if new succeeds but the constructor of the allocated object fails.
0

Share this post


Link to post
Share on other sites
Ok I found a way to pass the arguments in the delete operator by a global variables like this:

[source]#define DELETE_OLD delete
#define delete 0; while(bIsDeleteParamsPassing); bIsDeleteParamsPassing=true; chFile=(char*)__FILE__; inLineNo=__LINE__; DELETE_OLD[/source]

Here is the final version:

https://rapidshare.com/files/476519966/MemoryHandler.cpp

https://rapidshare.com/files/493613952/MemoryHandler.hpp

and example for used this (cmd) in main.cpp

https://rapidshare.com/files/1234352939/main.cpp Edited by sasho648
0

Share this post


Link to post
Share on other sites
Ugh... rapidshare...

[quote name='sasho648' timestamp='1348254408' post='4982465']
Ok I found a way to pass the arguments in the delete operator by a global variables like this:

[source]#define DELETE_OLD delete
#define delete 0; while(bIsDeleteParamsPassing); bIsDeleteParamsPassing=true; chFile=(char*)__FILE__; inLineNo=__LINE__; DELETE_OLD[/source]
[/quote]
Please don't.
[code]
#define DBG_DELETE delete(__FILE__, __LINE__)
#define delete DBG_DELETE
[/code]
[s]should work[/s] ([b]edit[/b]: turns out C++ doesn't support such syntax). If it doesn't, people can help you fix it... you didn't post the actual error when you said "This doesn't work." If you do, we can help you figure out what's up with it.

If you want some reasoning why I say the above code is bad, all you have to do is look at [font=courier new,courier,monospace]bIsDeleteParamsPassing[/font]... is that supposed to be some kind of mutex? You realize it doesn't work to protect your code in a multithreaded environment, right? I'm also unsure of why the [font=courier new,courier,monospace]0;[/font] is there...

And just a few more critiques on your code:[list]
[*]Be consistent with the std namespace. Sometimes you just say [font=courier new,courier,monospace]size_t[/font] instead of [font=courier new,courier,monospace]std::size_t[font=arial,helvetica,sans-serif]. You should always use the fully qualified [font=courier new,courier,monospace]std::[/font] prefix in header files (and also in source files, unless you do [font=courier new,courier,monospace]using namespace std[/font]).[/font][/font]
[*]If you're going to use global variables (which you shouldn't be), put them in a namespace
[*]Be consistent in your type names. Sometimes you use [font=courier new,courier,monospace]unsigned int[/font], sometimes [font=courier new,courier,monospace]UINT[/font]
[*]Consider using proper types for booleans (i.e. use [font=courier new,courier,monospace]false[/font] instead of [font=courier new,courier,monospace]0[/font] when assigning to a [font=courier new,courier,monospace]bool[/font])
[/list] Edited by Cornstalks
1

Share this post


Link to post
Share on other sites
Thank yoy very much for the critiques, this is exactly what I need because I learn c++ only from books and internet. The error behind "This doesn't work." is :
||=== Memw, Debug ===|
C:\Projects\Memw\main.cpp||In function 'int main()':|
C:\Projects\Memw\main.cpp|21|warning: left operand of comma operator has no effect [-Wunused-value]|
C:\Projects\Memw\main.cpp|21|error: type 'int' argument given to 'delete', expected pointer|
C:\Projects\Memw\main.cpp|21|error: expected ';' before 'my'|
||=== Build finished: 2 errors, 2 warnings ===|

at code:

[CODE]
using namespace std;
struct Some {
Some() {std::cout<<"constructor" <<std::endl;}
~Some() {std::cout<<"destructor" <<std::endl;}
unsigned long hash;
unsigned long hash1;
} ;
int main()
{
Some* my=new Some[2];
cout << "Hello world!" << endl;
delete my; //line 21
#ifdef DEBUG
EndOfProgramMemCheck();
#endif
system("PAUSE");
return 0;
}
[/CODE]


with defined
[CODE]
#define DBG_DELETE delete(__FILE__, __LINE__)
#define delete DBG_DELETE
[/CODE]

This means that the delete define expect pointer, not function call.

At Last: Can you give me better idea for the multithreaded environment importing (from bIsDeleteParamsPassing)?
0

Share this post


Link to post
Share on other sites
So here is my last update of this solution. Now it really support multithreading ( I use __thread variables ). Here is the source:

MemoryHandler.cpp

[CODE]
#include <iostream>
#include <windows.h>
#include <cstring>
#include <cstdio>
struct MemoryAllocList {
char* File;
unsigned int Line;
MemoryAllocList* next;
void* MemoryPointer;
} ;
struct LineFile {
unsigned int nLineNo;
char* szFile;
} ;
MemoryAllocList* & GetMemoryList()
{
static __thread MemoryAllocList* pAllocList(0);
return pAllocList;
}
MemoryAllocList** & GetMemoryCurrPtrList()
{
static __thread MemoryAllocList** ppCurAllocList(0);
return ppCurAllocList;
}
LineFile & GetDeleteParams()
{
static __thread LineFile Obj;
return Obj;
}
void* operator new(size_t size, const char* szFile, unsigned int nLineNo) _GLIBCXX_THROW (std::bad_alloc)
{
void* pMem;
while(true) {
pMem=malloc(size ? size : 1);
if(!pMem)
{
#ifdef WIN32_MEM_LOG
MessageBoxA(0, "No more memory to use!", "Warning!", MB_OK | MB_ICONWARNING);
#endif
#ifndef WIN32_MEM_LOG
std::cerr << "No more memory to use!" << "Warning!" << std::endl;
#endif
std::new_handler cach=std::set_new_handler(0);
if(cach) (*cach)();
else throw std::bad_alloc();
std::set_new_handler(cach);
}
else
break;
}
MemoryAllocList** & ppCurAllocList=GetMemoryCurrPtrList();
if(!ppCurAllocList) //Thread first new call
{
ppCurAllocList=&GetMemoryList();
}
while(*ppCurAllocList);
(*ppCurAllocList)=(MemoryAllocList*)malloc(sizeof(MemoryAllocList));
if(!(*ppCurAllocList))
{
#ifdef WIN32_MEM_LOG
MessageBoxA(0, "No more memory to use for the debug version of MemoryHandler. Try compiling the app \
in release mode. It will exit now!", "Error!", MB_OK | MB_ICONERROR);
#endif
#ifndef WIN32_MEM_LOG
std::cerr << "No more memory to use for the debug version of MemoryHandler. Try compiling the app \
in release mode. It will exit now!" << "Error!" << std::endl;
#endif
exit(1);
}
(*ppCurAllocList)->Line=nLineNo;
(*ppCurAllocList)->File=(char*)szFile;
(*ppCurAllocList)->MemoryPointer=pMem;
(*ppCurAllocList)->next=0;
ppCurAllocList=&(*ppCurAllocList)->next;
return pMem;
}
void* operator new[](size_t size, const char* szFile, unsigned int nLineNo) _GLIBCXX_THROW (std::bad_alloc)
{
return operator new(size, szFile, nLineNo);
}
void operator delete[](void* pMem) _GLIBCXX_USE_NOEXCEPT
{
operator delete(pMem);
}
bool PassDeleteParams (const char* szFile, unsigned int nLineNo)
{
LineFile & Obj(GetDeleteParams());
Obj.nLineNo=nLineNo;
Obj.szFile=(char*)szFile;
return false;
}
void operator delete(void* pMem) _GLIBCXX_USE_NOEXCEPT
{
LineFile CurrPos(GetDeleteParams());
if(!pMem) return;
MemoryAllocList* sourc(GetMemoryList());
while(sourc&&sourc->MemoryPointer!=pMem)
sourc=sourc->next;
if(!sourc)
{
#ifdef WIN32_MEM_LOG
char str[80];
sprintf(str, "Invalid delete call at File: %s Line: %d", CurrPos.szFile,
CurrPos.nLineNo);
MessageBoxA(0, str, "Warning!", MB_OK | MB_ICONWARNING);
#endif
#ifndef WIN32_MEM_LOG
std::cerr << "Invalid delete call at File: " << CurrPos.szFile << " Line: " << CurrPos.nLineNo << " Warning!" << std::endl;
#endif
return;
}
sourc->MemoryPointer=0;
free(pMem);
return;
}
void EndThreadMemCheck() {
MemoryAllocList* pCurAllocTree(GetMemoryList());
while(pCurAllocTree) {
if(pCurAllocTree->MemoryPointer) {
#ifndef WIN32_MEM_LOG
std::cerr << "Object at line: " << pCurAllocTree->Line << " in file: "
<< pCurAllocTree->File << " wasn't deleted!" << std::endl;
#endif
#ifdef WIN32_MEM_LOG
char str[80];
sprintf(str, "Object at line: %d in file: %s wasn't deleted!", pCurAllocTree->Line,
pCurAllocTree->File);
MessageBoxA(0, str, "Memory leaked!", MB_OK | MB_ICONWARNING);
#endif
}
MemoryAllocList* cach(pCurAllocTree);
pCurAllocTree=pCurAllocTree->next;
free(cach);
}
}
[/CODE]

MemoryHandler.hpp

[CODE]
#pragma once
/*Sasho 648 Memory leaks and inavlid delete calls finder (MultiThread support)
Set the MemoryHandler.cpp file to compile only in debug mode
and include the MemoryHandler.hpp only when the DEBUG symbol is defined. Then
at the end of a thread call EndThreadMemCheck() too when the DEBUG symbol is defined.
Define WIN32_MEM_LOG for Windows Messages.
*/
void* operator new(size_t size, const char* szFile, unsigned int nLineNo) _GLIBCXX_THROW (std::bad_alloc);
void* operator new[](size_t size, const char* szFile, unsigned int nLineNo) _GLIBCXX_THROW (std::bad_alloc);
void operator delete[](void* pMem) _GLIBCXX_USE_NOEXCEPT;
void operator delete(void* pMem) _GLIBCXX_USE_NOEXCEPT;
bool PassDeleteParams (const char* szFile, unsigned int nLineNo);
#define new new ( __FILE__ , __LINE__ )
#define DEL_OLD delete
#define delete if(PassDeleteParams(__FILE__, __LINE__)); else DEL_OLD
void EndThreadMemCheck() ;
[/CODE] Edited by sasho648
0

Share this post


Link to post
Share on other sites
You should wrap any statement-like macro into an single-looping do-while loop to ensure that the macro uses the exact same syntax and code paths as what it's trying to replace (the delete-statement in this case).

Consider things like this with your current code:
[code]
if(obj->isDead())
delete obj;
else
obj->update();
[/code]

The standard procedure to wrap macros that require a semicolon at the end is like this:
[code]
#define FOO do { /* code here, single or multiline-code */ } while(false)
[/code]
What this macro does is [b]forcing[/b] the user to end the macro call with a semicolon, just like you would have to do with the normal delete statement. Leaving out the semicolon after the macro call will produce a compiler error; the semicolon is not optional anymore as with regular macros. Furthermore, it does not introduce the possibility of an additional code path, and can therefore be used safely in nested constructs like for-loops and if-statements without introducing unexpected and unintended code paths.

An extra bonus is that the do-while loop has its own "private" scope for you to define variables in without affecting outside scope.
0

Share this post


Link to post
Share on other sites
[quote name='sasho648' timestamp='1348303369' post='4982612']
Thank yoy very much for the critiques, this is exactly what I need because I learn c++ only from books and internet. The error behind "This doesn't work." is :
||=== Memw, Debug ===|
C:\Projects\Memw\main.cpp||In function 'int main()':|
C:\Projects\Memw\main.cpp|21|warning: left operand of comma operator has no effect [-Wunused-value]|
C:\Projects\Memw\main.cpp|21|error: type 'int' argument given to 'delete', expected pointer|
C:\Projects\Memw\main.cpp|21|error: expected ';' before 'my'|
||=== Build finished: 2 errors, 2 warnings ===|
[...]
with defined
[CODE]
#define DBG_DELETE delete(__FILE__, __LINE__)
#define delete DBG_DELETE
[/CODE]
[/quote]

The first parameter for delete is a void*. That's what the message tells you. So the call to your overriden delete (which should probably look something like this:
[CODE]
void* operator delete(void*, const char* szFile, unsigned int nLineNo);
[/CODE]
) you'd need to write
[CODE]
delete(myObject, __FILE__, __LINE__);
[/CODE]
However your macro will do this:
[CODE]
delete myObject;
// will be expanded to
delete(__FILE__, __LINE__) myObject;
[/CODE]
Apparently this is not correct.

I just checked, and even the
[CODE]
delete(myObject, __FILE__, __LINE__);
[/CODE]
gives a compile error in visual studio ("Cannot delete objects that are no pointers") for whatever reason.

The code
[CODE]
delete(__FILE__, __LINE__, myObject);
[/CODE]
Compiles but doesn't call my delete, but the default delete operator.

So anyway. Here's my suggestion:
[CODE]
#include <iostream>
class Foo {
public:
Foo() {}
};
void* operator new(size_t size, const char* f, unsigned int line) {
std::cout << "new: " << f << ":" << line << std::endl;
return malloc(size);
}
// just here to avoid the warning "'void *operator new(size_t,const char *,unsigned int)' : no matching operator delete found; memory will not be freed if initialization throws an exception"
void operator delete(void* ptr, const char* f, unsigned int line) {
std::cout << "delete: " << f << ":" << line << std::endl;
return free(ptr);
}
void Destroy(void* ptr, const char* f, unsigned int line) {
std::cout << "delete: " << f << ":" << line << std::endl;
return free(ptr);
}
#define DBG_NEW new(__FILE__, __LINE__)
#define new DBG_NEW
#define DBG_DELETE(p) Destroy(p, __FILE__, __LINE__)
#define delete(p) DBG_DELETE(p)
int main() {
Foo* myFoo = new Foo();
delete(myFoo);
return 0;
}
[/CODE]
0

Share this post


Link to post
Share on other sites
@Brother Bob Thanks for the problem respond but I don't understand how do {} while() loop will help me.
@brx With your solution the user need to type () after the delete but the most delete calls are without them.

Here is my solution (which I'll correct in my last post):

[CODE]
#define DEL_OLD delete
#define delete if(PassDeleteParams(__FILE__, __LINE__)); else DEL_OLD
[/CODE]

The problem now is more complex - the threads in the program can assign dynamicly created object on an global variables like this:

[CODE]
char* String;
unsigned long __stdcall Thread1 (void* lp)
{
String=new char[50];
#ifdef DEBUG
EndThreadMemCheck();
#endif
return 0;
}
[/CODE]

In this case it will give an error for an memory leak and when I delete it from the main thread it will give me message for an invalid delete call. Any suggestions to avoid this? Edited by sasho648
0

Share this post


Link to post
Share on other sites
[quote name='sasho648' timestamp='1348678330' post='4984016']
@Brother Bob Thanks for the problem respond but I don't understand how do {} while() loop will help me.
[/quote]
When it comes to calling macros, it doesn't force the use of a semicolon. It is never an error, nor is it never required, to call a macro with or without a semicolon; nor can you force any single convention upon the macro call itself. What the macro expands to for the compiler, however, may or may not require a semicolon.

The purpose of the do-while construct is to force the convention of a semicolon after the macro call just like you are forced to have a semicolon after a delete statement.

Now, I did overlook the else-statement in your macro so the comment to your particular macro was not correct. I believe it does expand correctly in any situation where the delete-syntax is correct. I would, however, suggest that if you take the advice with the do-while loop construct for any further macro that has any sort of local scope or control structure as the base of the macro.
0

Share this post


Link to post
Share on other sites
[quote name='sasho648' timestamp='1348678330' post='4984016']
@Brother Bob Thanks for the problem respond but I don't understand how do {} while() loop will help me.

Here is my solution (which I'll correct in my last post):

[CODE]
#define DEL_OLD delete
#define delete if(PassDeleteParams(__FILE__, __LINE__)); else DEL_OLD
[/CODE]
[/quote]
I suggest a normal [font=courier new,courier,monospace]do {} while (false)[/font], simply because it's more idiomatic. Particularly, some compilers may generate a warning about the [font=courier new,courier,monospace]if (true);[/font] body being empty. But it's up to you, I don't see a particular issue with that method.

Sorry I misled you on placement delete. It turns out that the syntax [font=courier new,courier,monospace]delete(params) ptr;[/font] is not supported in C++, which is why the macro was having issues with delete.

One more thing: you should use [font=courier new,courier,monospace]NULL[/font] (or [font=courier new,courier,monospace]nullptr[/font] if using C++11) for null pointers. 0 works, but [font=courier new,courier,monospace]NULL[/font]/[font=courier new,courier,monospace]nullptr[/font] are preferred in practice.

I don't know much about your threading issue as I've never used [font=courier new,courier,monospace]__thread[/font] before, sorry I'm not much help there.
0

Share this post


Link to post
Share on other sites
[quote name='fastcall22' timestamp='1347379780' post='4978942']
[img]http://img405.imageshack.us/img405/4421/skijl.png[/img]
[/quote]

HAHAHAHA!!! I was just watching that episode the other day lol! Sorry, but you literally made me LOL... XD
0

Share this post


Link to post
Share on other sites
[quote name='BinaryPhysics' timestamp='1347451873' post='4979274']
[quote name='sasho648' timestamp='1347299520' post='4978639'][source]MessageBoxA(0, str, "Memory leaked!", MB_OK | MB_ICONWARNING);[/source][/quote]

You make this call multiple times. Don't. Just use 'MessageBox'. The reason that there's a macro defining the name is for character width (I think).
[/quote]

The macro just resolves to either MessageBoxA() or MessageBoxW() depending on the compiler's set character width. If he's giving it a string literal it's best to call MessageBoxA().
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0