March 2, 2011

Debith Debith
Lab Rat
4 posts

Overriding new and delete operator

 

Hi!

I’m working on QT and I’m currently writing test application to our code. We decided to try to detect also memory leaks with our objects, so we have overridden new and delete operators in following way.

  1. // main.cpp
  2.  
  3. void * operator new(unsigned int size) throw (std::bad_alloc)
  4. {
  5.     void *ptr = (void *)malloc(size);
  6.     Pointers::instance()->append(ptr);
  7.     return(ptr);
  8. };
  9.  
  10. void operator delete(void *p) throw()
  11. {
  12.     Pointers::instance()->removeAll(p);
  13.     free(p);
  14. };

class Pointers is singleton class, containing list of all allocated pointers. Because memory leaks are easy to detect from test cases, we keep only track about number of pointers.

The Problem is:

  1. // test.cpp
  2.  
  3. void TestClass::testCanary() {
  4.     QVERIFY(true);
  5.  
  6.     // Makes sure that environment works for new and delete -operators.
  7.     QCOMPARE(NUM_POINTERS(), 0);
  8.     int *i = new int(2);
  9.     QCOMPARE(NUM_POINTERS(), 1);
  10.     delete i;
  11.     QCOMPARE(NUM_POINTERS(), 0);
  12.     QWidget *w = new QWidget();
  13.     QCOMPARE(NUM_POINTERS(), 1);
  14.     delete w;
  15.     QCOMPARE(NUM_POINTERS(), 0); // <------ FAILS!!!???
  16. }

The marked line fails and this happens only, when compiling code with Mingw32-make (GNU Make 3.81) coming with QT 4.7 packet. On Visual Studio 2008, the test passes.

[edit] please use @ for code

6 replies

March 3, 2011

Franzk Franzk
Lab Rat
830 posts

What does NUM_POINTERS() return?

 Signature 

“Horse sense is the thing a horse has which keeps it from betting on people.”—W.C. Fields

http://www.catb.org/~esr/faqs/smart-questions.html

March 3, 2011

Debith Debith
Lab Rat
4 posts

#define NUM_POINTERS() Pointers::instance()->count()

March 3, 2011

Debith Debith
Lab Rat
4 posts

Some more information…

This does not work:

  1. // test.cpp
  2.  
  3. void TestClass::testCanary() {
  4.     QVERIFY(true);
  5.  
  6.     // Makes sure that environment works for new and delete -operators.
  7.     QCOMPARE(NUM_POINTERS(), 0);
  8.     int *i = new int(2);
  9.     QCOMPARE(NUM_POINTERS(), 1);
  10.     delete i;
  11.     QCOMPARE(NUM_POINTERS(), 0);
  12.     QWidget *w = new QWidget();
  13.     QCOMPARE(NUM_POINTERS(), 1);
  14.     delete w;
  15.     QCOMPARE(NUM_POINTERS(), 0); // <------ FAILS!!!???
  16. }

But this works:

  1.  
  2. // test.cpp
  3.  
  4. void TestClass::testCanary() {
  5.     QVERIFY(true);
  6.  
  7.     // Makes sure that environment works for new and delete -operators.
  8.     QCOMPARE(NUM_POINTERS(), 0);
  9.     int *i = new int(2);
  10.     QCOMPARE(NUM_POINTERS(), 1);
  11.     delete i;
  12.     QCOMPARE(NUM_POINTERS(), 0);
  13.     QWidget *w = new QWidget();
  14.     QCOMPARE(NUM_POINTERS(), 1);
  15.     ::delete w;                  // <------ notice ::
  16.     QCOMPARE(NUM_POINTERS(), 0); // <------ SUCCEEDS!!!
  17. }

Anyone can explain? Of course, it is not solution to add ‘::’ everywhere in the code.

March 3, 2011

Franzk Franzk
Lab Rat
830 posts

maybe QWidget or QObject has the delete operator overloaded? It seems like a bit of odd behavior at least.

 Signature 

“Horse sense is the thing a horse has which keeps it from betting on people.”—W.C. Fields

http://www.catb.org/~esr/faqs/smart-questions.html

March 3, 2011

Franzk Franzk
Lab Rat
830 posts

Hmmno.

I used the following code:

  1. #include <QApplication>
  2. #include <QWidget>
  3. #include <QDebug>
  4.  
  5. int ptrs = 0;
  6.  
  7. void * operator new(size_t size) throw (std::bad_alloc)
  8. {
  9.  void *ptr = (void *)malloc(size);
  10.  ptrs++;
  11.  return(ptr);
  12. };
  13.  
  14. void operator delete(void *p) throw()
  15. {
  16.  ptrs--;
  17.  free(p);
  18. };
  19.  
  20. int main(int argc, char *argv[])
  21. {
  22.  QApplication app(argc, argv);
  23.  qDebug() << ptrs;
  24.  QWidget *w = new QWidget;
  25.  qDebug() << ptrs;
  26.  delete w;
  27.  qDebug() << ptrs;
  28. }

Which resulted in the following output:

  1. 1101
  2. 1107
  3. 1104

That probably means that you cannot assume that the amount you expect is almost always wrong…

Anyway, in which objects do you expect memory leaks?

 Signature 

“Horse sense is the thing a horse has which keeps it from betting on people.”—W.C. Fields

http://www.catb.org/~esr/faqs/smart-questions.html

March 3, 2011

Debith Debith
Lab Rat
4 posts

Full source here

unittest_operatortest.pro

  1. CONFIG += qtestlib console
  2.  
  3. DEFINES += BUILD_QTILIB
  4.  
  5. SOURCES += main.cpp
  6. SOURCES += unittest_operatortest.cpp
  7.  
  8. HEADERS += unittest_operatortest.h

unittest_operatortest.h

  1. #ifndef UNITTEST_OPERATORTEST
  2. #define UNITTEST_OPERATORTEST
  3.  
  4. #include <QObject>
  5. #include <new>
  6.  
  7. /*********************************************************************
  8.  * DECLARATIONS
  9.  *********************************************************************/
  10.  
  11. void * operator new(unsigned int size) throw (std::bad_alloc);
  12. void operator delete(void*) throw();
  13. void* operator new(size_t size, const std::nothrow_t&) throw ();
  14. void operator delete(void* ptr, const std::nothrow_t&) throw ();
  15.  
  16. class Pointers : public QObject
  17. {
  18. public:
  19.     static QList<void *>* instance();
  20.     static void release();
  21. };
  22.  
  23. #define MARK() Pointers::instance()->clear()
  24. #define NUM_POINTERS() Pointers::instance()->count()
  25.  
  26. /*********************************************************************
  27.  * TEST CLASS
  28.  *********************************************************************/
  29.  
  30. class UnittestOperatorTest : public QObject
  31. {
  32.     Q_OBJECT
  33.  
  34.     private slots:
  35.         void init();
  36.         void cleanup();
  37.  
  38.     // Test cases
  39.         void testCanary();
  40. };
  41.  
  42. #endif // UNITTEST_OPERATORTEST

unittest_operatortest.cpp

  1. #include "unittest_operatortest.h"
  2.  
  3. #include <QApplication>
  4. #include <QtTest/QTest>
  5. #include <QDebug>
  6.  
  7. /*********************************************************************
  8.  * POINTER CLASS IMPLEMENTATION
  9.  *********************************************************************/
  10.  
  11. static QList<void *>* globalAllocationList = NULL;
  12.  
  13. QList<void *>* Pointers::instance()
  14. {
  15.    if ( !globalAllocationList ) {
  16.        globalAllocationList = static_cast<QList<void*>*>(malloc(sizeof(new QList<void *>)));
  17.        new (globalAllocationList) QList <void*>;
  18.    }
  19.    return globalAllocationList;
  20. }
  21.  
  22. void Pointers::release()
  23. {
  24.     globalAllocationList->~QList();
  25.     free(globalAllocationList);
  26.     globalAllocationList = NULL;
  27. }
  28.  
  29. /*********************************************************************
  30.  * TEST CASES
  31.  *********************************************************************/
  32.  
  33. void UnittestOperatorTest::init() {
  34.     MARK();
  35. }
  36.  
  37. void UnittestOperatorTest::cleanup() {
  38. }
  39.  
  40. void UnittestOperatorTest::testCanary() {
  41.     QVERIFY(true);
  42.  
  43.     // Makes sure that environment works for new and delete -operators.
  44.     QCOMPARE(NUM_POINTERS(), 0);
  45.     int *i = new int(2);
  46.     QCOMPARE(NUM_POINTERS(), 1);
  47.     delete i;
  48.     QCOMPARE(NUM_POINTERS(), 0);
  49.     QWidget *w = new QWidget();
  50.     QCOMPARE(NUM_POINTERS(), 1);
  51.     delete w;
  52.     QCOMPARE(NUM_POINTERS(), 0);
  53. }

main.cpp

  1. #include "unittest_operatortest.h"
  2.  
  3. #include <QtTest/QTest>
  4. #include <QApplication>
  5.  
  6. /*********************************************************************
  7.  * OVERRIDE CODE
  8.  *********************************************************************/
  9.  
  10. void * operator new(unsigned int size) throw (std::bad_alloc)
  11. {
  12.     void *ptr = (void *)malloc(size);
  13.     Pointers::instance()->append(ptr);
  14.     return(ptr);
  15. };
  16.  
  17. void operator delete(void *p) throw()
  18. {
  19.     Pointers::instance()->removeAll(p);
  20.     free(p);
  21. };
  22.  
  23. void * operator new(unsigned int size, const std::nothrow_t&) throw ()
  24. {
  25.     void *ptr = (void *)malloc(size);
  26.     Pointers::instance()->append(ptr);
  27.     return(ptr);
  28. };
  29.  
  30. void operator delete(void *p, const std::nothrow_t&) throw()
  31. {
  32.     Pointers::instance()->removeAll(p);
  33.     free(p);
  34. };
  35.  
  36. /*********************************************************************
  37.  * MAIN FUNCTION
  38.  *********************************************************************/
  39.  
  40. int main(int argc, char *argv[])
  41. {
  42.     QApplication app(argc, argv);
  43.     int ret = 0;
  44.  
  45.     UnittestOperatorTest testableClass;
  46.     ret = QTest::qExec(&testableClass, argc, argv);
  47.  
  48.     return ret;
  49. }

 
  ‹‹ calculating Adjacent matrix      Qt Eclipse Integration iostream unresolved inclusion ››

You must log in to post a reply. Not a member yet? Register here!