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.

    @
    // main.cpp

    void * operator new(unsigned int size) throw (std::bad_alloc)
    {
    void *ptr = (void *)malloc(size);
    Pointers::instance()->append(ptr);
    return(ptr);
    };

    void operator delete(void *p) throw()
    {
    Pointers::instance()->removeAll(p);
    free(p);
    };
    @

    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:

    @
    // test.cpp

    void TestClass::testCanary() {
    QVERIFY(true);

    // Makes sure that environment works for new and delete -operators.
    QCOMPARE(NUM_POINTERS(), 0);
    int *i = new int(2);
    QCOMPARE(NUM_POINTERS(), 1);
    delete i;
    QCOMPARE(NUM_POINTERS(), 0);
    QWidget *w = new QWidget();
    QCOMPARE(NUM_POINTERS(), 1);
    delete w;
    QCOMPARE(NUM_POINTERS(), 0); // <------ FAILS!!!???
    

    }
    @

    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



  • What does NUM_POINTERS() return?



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



  • Some more information...

    This does not work:
    @
    // test.cpp

    void TestClass::testCanary() {
    QVERIFY(true);

    // Makes sure that environment works for new and delete -operators.
    QCOMPARE(NUM_POINTERS(), 0);
    int *i = new int(2);
    QCOMPARE(NUM_POINTERS(), 1);
    delete i;
    QCOMPARE(NUM_POINTERS(), 0);
    QWidget *w = new QWidget();
    QCOMPARE(NUM_POINTERS(), 1);
    delete w;
    QCOMPARE(NUM_POINTERS(), 0); // <------ FAILS!!!???
    

    }
    @

    But this works:

    @
    // test.cpp

    void TestClass::testCanary() {
    QVERIFY(true);

    // Makes sure that environment works for new and delete -operators.
    QCOMPARE(NUM_POINTERS(), 0);
    int *i = new int(2);
    QCOMPARE(NUM_POINTERS(), 1);
    delete i;
    QCOMPARE(NUM_POINTERS(), 0);
    QWidget *w = new QWidget();
    QCOMPARE(NUM_POINTERS(), 1);
    ::delete w;                  // <------ notice ::
    QCOMPARE(NUM_POINTERS(), 0); // <------ SUCCEEDS!!!
    

    }
    @

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



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



  • Hmmno.

    I used the following code:
    @
    #include <QApplication>
    #include <QWidget>
    #include <QDebug>

    int ptrs = 0;

    void * operator new(size_t size) throw (std::bad_alloc)
    {
    void *ptr = (void *)malloc(size);
    ptrs++;
    return(ptr);
    };

    void operator delete(void *p) throw()
    {
    ptrs--;
    free(p);
    };

    int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);
    qDebug() << ptrs;
    QWidget *w = new QWidget;
    qDebug() << ptrs;
    delete w;
    qDebug() << ptrs;
    }
    @

    Which resulted in the following output:
    @1101
    1107
    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?



  • Full source here

    unittest_operatortest.pro
    @
    CONFIG += qtestlib console

    DEFINES += BUILD_QTILIB

    SOURCES += main.cpp
    SOURCES += unittest_operatortest.cpp

    HEADERS += unittest_operatortest.h
    @

    unittest_operatortest.h
    @
    #ifndef UNITTEST_OPERATORTEST
    #define UNITTEST_OPERATORTEST

    #include <QObject>
    #include <new>

    /*********************************************************************

    • DECLARATIONS
      *********************************************************************/

    void * operator new(unsigned int size) throw (std::bad_alloc);
    void operator delete(void*) throw();
    void* operator new(size_t size, const std::nothrow_t&) throw ();
    void operator delete(void* ptr, const std::nothrow_t&) throw ();

    class Pointers : public QObject
    {
    public:
    static QList<void > instance();
    static void release();
    };

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

    /*********************************************************************

    • TEST CLASS
      *********************************************************************/

    class UnittestOperatorTest : public QObject
    {
    Q_OBJECT

    private slots:
        void init();
        void cleanup();
    
    // Test cases
        void testCanary();
    

    };

    #endif // UNITTEST_OPERATORTEST
    @

    unittest_operatortest.cpp
    @
    #include "unittest_operatortest.h"

    #include <QApplication>
    #include <QtTest/QTest>
    #include <QDebug>

    /*********************************************************************

    • POINTER CLASS IMPLEMENTATION
      *********************************************************************/

    static QList<void > globalAllocationList = NULL;

    QList<void > Pointers::instance()
    {
    if ( !globalAllocationList ) {
    globalAllocationList = static_cast<QList<void*>*>(malloc(sizeof(new QList<void >)));
    new (globalAllocationList) QList <void
    >;
    }
    return globalAllocationList;
    }

    void Pointers::release()
    {
    globalAllocationList->~QList();
    free(globalAllocationList);
    globalAllocationList = NULL;
    }

    /*********************************************************************

    • TEST CASES
      *********************************************************************/

    void UnittestOperatorTest::init() {
    MARK();
    }

    void UnittestOperatorTest::cleanup() {
    }

    void UnittestOperatorTest::testCanary() {
    QVERIFY(true);

    // Makes sure that environment works for new and delete -operators.
    QCOMPARE(NUM_POINTERS(), 0);
    int *i = new int(2);
    QCOMPARE(NUM_POINTERS(), 1);
    delete i;
    QCOMPARE(NUM_POINTERS(), 0);
    QWidget *w = new QWidget();
    QCOMPARE(NUM_POINTERS(), 1);
    delete w;
    QCOMPARE(NUM_POINTERS(), 0);
    

    }
    @

    main.cpp
    @
    #include "unittest_operatortest.h"

    #include <QtTest/QTest>
    #include <QApplication>

    /*********************************************************************

    • OVERRIDE CODE
      *********************************************************************/

    void * operator new(unsigned int size) throw (std::bad_alloc)
    {
    void *ptr = (void *)malloc(size);
    Pointers::instance()->append(ptr);
    return(ptr);
    };

    void operator delete(void *p) throw()
    {
    Pointers::instance()->removeAll(p);
    free(p);
    };

    void * operator new(unsigned int size, const std::nothrow_t&) throw ()
    {
    void *ptr = (void *)malloc(size);
    Pointers::instance()->append(ptr);
    return(ptr);
    };

    void operator delete(void *p, const std::nothrow_t&) throw()
    {
    Pointers::instance()->removeAll(p);
    free(p);
    };

    /*********************************************************************

    • MAIN FUNCTION
      *********************************************************************/

    int main(int argc, char *argv[])
    {
    QApplication app(argc, argv);
    int ret = 0;

    UnittestOperatorTest testableClass;
    ret = QTest::qExec(&testableClass, argc, argv&#41;;
    
    return ret;
    

    }
    @


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.