Results 1 to 7 of 7

Thread: c++, placement delete upon exception

  1. #1
    Join Date
    Sep 2006
    Posts
    27
    Thanks
    1
    Thanked 2 Times in 1 Post
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default c++, placement delete upon exception

    Hi All!

    I'm having this really nasty problem regarding placement new and delete; more specific: with cleaning up the memory when an exception is thrown in the constructor of a class.

    Here's a test class declaring it's own placement new and delete versions:
    Qt Code:
    1. class memtest
    2. {
    3. public:
    4. //non-placement overloads omitted
    5. static void* operator new( size_t, void* p )
    6. { return p; }
    7. static void operator delete( void* p, void* )
    8. { ( (memtest*) p )->~memtest(); free( p ); }
    9. static void* operator new [] ( size_t, void* p )
    10. { return p; }
    11. static void operator delete [] ( void* p, void* )
    12. { /* and now ? */ }
    13.  
    14. memtest() :
    15. a( new int )
    16. {
    17. throw( 0 );
    18. }
    19.  
    20. ~memtest()
    21. {
    22. delete a;
    23. }
    24. };
    To copy to clipboard, switch view to plain text mode 

    Now, working with single objects is no big problem, as the compiler generates code to call the corresponding placement delete when the exception is thrown:

    Qt Code:
    1. int main()
    2. {
    3. try
    4. {
    5. memtest* pMem = (memtest*) malloc( sizeof( memtest ) ); //allocate mem
    6. new( pMem ) memtest; //calls placement new and new handler
    7. delete pMem; //won't be reached due to constructor failure
    8. }
    9. catch(...)
    10. {
    11. //no mem leak, compiler generated code called memtest::operator delete( void* p, void* )
    12. }
    13. }
    To copy to clipboard, switch view to plain text mode 

    The problem arises when using placement new [] and delete []: the compiler will also correctly generate code to call operator delete [] ( void*, void* ), but what am I supposed to put in there?

    Qt Code:
    1. int main()
    2. {
    3. try
    4. {
    5. memtest* pMem = (memtest*) malloc( sizeof( memtest ) * 2 + sizeof( size_t ) ); //allocate mem
    6. pMem = new( pMem ) memtest[ 2 ]; //calls placement new[] and iterates it with new handler
    7. delete [] pMem; //won't be reached
    8. }
    9. catch(...)
    10. {
    11. //memleak or crash ??
    12. }
    13. }
    To copy to clipboard, switch view to plain text mode 

    If I would use

    Qt Code:
    1. operator delete [] ( void* p, void* )
    2. {
    3. free( p );
    4. }
    To copy to clipboard, switch view to plain text mode 

    it will free the allocated memory, but memtest's destructor won't get called, resulting in memtest::a leaking.

    If I'd put something like this:

    Qt Code:
    1. operator delete [] ( void* p, void* )
    2. {
    3. size_t* pSecretSize = ((size_t*) p) - 1; //new [] stores size in front of array
    4. for( size_t i = 0 ; i < *pSecretSize ; ++i )
    5. (&(mem)[i])->~memtest(); //call destructor
    6. free( pSecretSize ) ; //free
    7. }
    To copy to clipboard, switch view to plain text mode 

    then it will call the destructor for all elements in the array, and afterwards nicely free the memory.
    However, when this gets called from within the constructor, there are two problems:
    - at first, p will still point to the beginning of the array memory, not to the beginning of the array, so the pSecretSize stuff is completely wrong
    - second, even if the pointer passed pointed to the beginning of the array, the code crashes the program since it calls destructors of objects that are not constructed.

    Am I missing something, or is it just impossible to not have a leak when using the vector new and delete ?

  2. #2
    Join Date
    Feb 2006
    Location
    Oslo, Norway
    Posts
    6,264
    Thanks
    36
    Thanked 1,518 Times in 1,388 Posts
    Qt products
    Qt4
    Platforms
    MacOS X Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: c++, placement delete upon exception

    - Why are you mixing malloc/free and new/delete?
    - You should never explicitly call the destructor of a class..
    - Is there any specific reason for writing your own complex new/delete operators?

    Am I missing something here? Why don't you simply cleanup the members before throwing an exception? Or use auto/smart pointer or reference counting techniques.

    How should I handle resources if my constructors may throw exceptions?

    It should be as simple as this to handle the cleanup upon exception:
    Qt Code:
    1. Something* some = 0;
    2. try {
    3. some = new Something[n];
    4. }
    5. catch (...)
    6. {
    7. delete[] some;
    8. some = 0;
    9. }
    To copy to clipboard, switch view to plain text mode 
    J-P Nurmi

  3. #3
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 975 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: c++, placement delete upon exception

    Quote Originally Posted by stinos View Post
    it will free the allocated memory, but memtest's destructor won't get called, resulting in memtest::a leaking.
    Are you sure?
    Qt Code:
    1. #include <cstddef>
    2. #include <iostream>
    3.  
    4. class Test
    5. {
    6. public:
    7. Test()
    8. {
    9. static int next_id = 0;
    10. id = ++next_id;
    11. std::cerr << __PRETTY_FUNCTION__ << '(' << id << ')' << std::endl;
    12. if( id == 4 ) throw 1;
    13. }
    14.  
    15. ~Test()
    16. {
    17. std::cerr << __PRETTY_FUNCTION__ << '(' << id << ')' << std::endl;
    18. }
    19.  
    20. static void * operator new[]( size_t, Test *pool )
    21. {
    22. std::cerr << __PRETTY_FUNCTION__ << std::endl;
    23. return pool;
    24. }
    25.  
    26. static void operator delete []( void *, Test * )
    27. {
    28. std::cerr << __PRETTY_FUNCTION__ << std::endl;
    29. }
    30.  
    31. private:
    32. int id;
    33. };
    34.  
    35. int main()
    36. {
    37. size_t count = 5;
    38. char buffer[ sizeof( size_t ) + count * sizeof( Test ) ];
    39.  
    40. try {
    41. Test *t = new( (Test*)buffer ) Test[ count ];
    42. }
    43. catch(...)
    44. {
    45. }
    46.  
    47. std::cerr << "done" << std::endl;
    48.  
    49. return 0;
    50. }
    To copy to clipboard, switch view to plain text mode 

    Output:
    $ ./a.out
    static void* Test::operator new [](unsigned int, Test*)
    Test::Test()(1)
    Test::Test()(2)
    Test::Test()(3)
    Test::Test()(4)
    Test::~Test()(3)
    Test::~Test()(2)
    Test::~Test()(1)
    static void Test::operator delete [](void*, Test*)
    done
    It looks like it behaves just like ordinary new[] (note that the destructor won't be called for the object that threw the exception, as that object isn't fully constructed).

    You can find some interesting information about placement new here: http://www.parashift.com/c++-faq-lit...html#faq-11.14 and of course in Lippman's C++ Primer.

  4. #4
    Join Date
    Sep 2006
    Posts
    27
    Thanks
    1
    Thanked 2 Times in 1 Post
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: c++, placement delete upon exception

    fisrt, thanks for the replies. Jacek, your example is quite interesting.
    second, as I reread my post now I slapped myself in the face a few times, I was obviously not thinking clearly at the time of writing it, it's complete bollocks (very likely due to coding 18 hours in row combined with heavy drugs I have to take due to a recent accident).


    Quote Originally Posted by jpn View Post
    - Why are you mixing malloc/free and new/delete?
    for the reason above I fear

    Quote Originally Posted by jpn View Post
    - You should never explicitly call the destructor of a class..
    possibly, but it's the only way to destruct something when using placement new, I think.

    Quote Originally Posted by jpn View Post
    - Is there any specific reason for writing your own complex new/delete operators?
    there are two: first, I'm quite addicted to learning all details, writing the operators myself learned me a lot about new/delete, before I didn't even know you can actually have an unlimited number of overloads of them, next to the standard eight. After this post everything became quite clear..
    second, I'm using custom allocators all over the place so I have to overwrite them in order to let them use myallocator::malloc etc

    btw I found http://msdn.microsoft.com/library/de...deep080599.asp to be very interesting and in-depth too.

  5. #5
    Join Date
    Sep 2006
    Posts
    27
    Thanks
    1
    Thanked 2 Times in 1 Post
    Qt products
    Qt3 Qt4 Qt/Embedded
    Platforms
    MacOS X Unix/X11 Windows

    Default Re: c++, placement delete upon exception

    Jacek, just tested your code and it works as expected indeed; however, it didn't compile at first:
    - line 38 generates "error: expression must have a constant value" with cl (microsoft) and cl6x (texas instruments); I didn't know it was ok for gcc?
    - __PRETTY_FUNCTION__ is g++ specific

    anyway, thanks again!

  6. #6
    Join Date
    May 2006
    Location
    Germany
    Posts
    108
    Thanks
    2
    Thanked 14 Times in 12 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: c++, placement delete upon exception

    Quote Originally Posted by stinos View Post
    - line 38 generates "error: expression must have a constant value" with cl (microsoft) and cl6x (texas instruments); I didn't know it was ok for gcc?
    Qt Code:
    1. size_t count = 5;
    2. char buffer[ sizeof( size_t ) + count * sizeof( Test ) ];
    To copy to clipboard, switch view to plain text mode 

    That looks like a very constant expression though. Naughty ms/ti compilers.

    *edit* ah no, count ain't const.

  7. #7
    Join Date
    Aug 2006
    Location
    Zürich, Switzerland
    Posts
    23
    Thanks
    1
    Thanked 1 Time in 1 Post
    Qt products
    Qt4
    Platforms
    Unix/X11 Windows

    Default Re: c++, placement delete upon exception

    The discussion about mixing new and malloc reminded me of when we recently had to port an existing application to a new platform with different compilers than used before. Building the app wasn't a problem, but running it was a nightmare because it crashed randomly. So after digging deep into the code, which was written in different languages and spread over several libraries, we found out that the problem indeed was a new/malloc mix. More details from a C++ expert with name Stroustrup can be found on his website:

    http://www.research.att.com/~bs/bs_faq2.html#realloc

Similar Threads

  1. When is the best time to delete a QCanvasItem
    By irudkin in forum Qt Programming
    Replies: 12
    Last Post: 8th March 2007, 21:28
  2. Delete all members in a QGraphicsItemGroup
    By vmferreira in forum Qt Programming
    Replies: 3
    Last Post: 17th August 2006, 18:47
  3. QListWidget + Delete Key
    By bpetty in forum Newbie
    Replies: 5
    Last Post: 16th August 2006, 20:38
  4. How to explicitely delete a QDir?
    By alan in forum Newbie
    Replies: 2
    Last Post: 13th February 2006, 17:48
  5. Exceptions and qApp->processEvents()
    By mcostalba in forum Qt Programming
    Replies: 3
    Last Post: 8th January 2006, 17:06

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.