Heap Manager and new/delete overloading

Discussion in 'C++' started by silver360@gmail.com, Dec 20, 2005.

  1. Guest

    Hello,
    I'm trying to create a basic Heap manager and i have some question
    about new/delete overloading.
    The following code give me this output :
    >> $./heap
    >> registered : 0x804d098
    >> 0x804d008 _Delete unknown block
    >> registered : 0x804d138
    >> 0x804d008 _Delete unknown block
    >> 0x804d098 _Delete ok
    >> 0x804d0a8 _Delete unknown block
    >> 0x804d138 _Delete ok
    >> 0x804d148 _Delete unknown block


    Why is the HeapManager::_Delete called to delete objects that weren't
    created using HeapManager::_New ?
    The only reason I see is that these calls come from my BlocksMap
    internals. Is it possible to differenciate delete used by the libstdc++
    and delete used by the parts of my programs which are after the
    overloading ?
    Thanks for any advice :)
    Silver

    ------------------------------------------------
    #include <map>
    #include <vector>
    #include <stdlib.h>
    #include <string>
    #include <string.h>
    #include <iostream>

    using namespace std;

    class HeapManager
    {
    public:
    struct BlockDescriptor {
    size_t size;
    char filename[100];
    int line;
    };
    static HeapManager* pSelf;
    ~HeapManager ();
    void* _New (size_t size, const string& filename, int line);
    void _Delete (void* addr);
    private:
    typedef map<void*, BlockDescriptor*> t_blocksMap;
    t_blocksMap BlocksMap;
    };

    HeapManager::~HeapManager ()
    {
    vector<t_blocksMap::iterator> toErase;
    t_blocksMap::iterator i;
    for(i=BlocksMap.begin(); i!=BlocksMap.end(); i++) {
    cout << "leak : " << i->second->filename << ":" << i->second->line
    <<endl;
    free(i->second);
    free(i->first);
    toErase.push_back(i);
    }
    for(unsigned int j =0; j<toErase.size(); j++) {
    BlocksMap.erase(toErase[j]);
    }
    }

    void* HeapManager::_New(size_t size, const string& filename, int line)
    {
    if(size <= 0)
    return 0;

    BlockDescriptor* pDesc =
    (BlockDescriptor*)malloc(sizeof(BlockDescriptor));
    pDesc->size = size;
    strncpy(pDesc->filename,filename.data(),99);
    pDesc->filename[99] = '\0';
    pDesc->line = line;
    void* block = malloc(size);
    BlocksMap.insert(make_pair(block,pDesc));
    cout << "registered : " << block << endl;
    return block;
    }

    void HeapManager::_Delete(void* addr)
    {
    if(addr == 0)
    return;
    cout << addr << " ";
    t_blocksMap::iterator i = BlocksMap.find(addr);
    if (i != BlocksMap.end()) {
    cout << "_Delete ok " << endl;
    free(i->second);
    BlocksMap.erase(i);
    } else {
    cout << "_Delete unknown block" << endl;
    }
    free(addr);
    }

    void* operator new(size_t size, const string& filename, int line) {
    return HeapManager::pSelf->_New(size, filename, line);
    }

    void* operator new[](size_t size, const string& filename, int line) {
    return HeapManager::pSelf->_New(size, filename, line);
    }

    void operator delete (void* addr) {
    HeapManager::pSelf->_Delete(addr);
    }

    void operator delete [] (void* addr) {
    HeapManager::pSelf->_Delete(addr);
    }

    #define new new(__FILE__,__LINE__)

    HeapManager* HeapManager::pSelf = NULL;
    HeapManager theHeap;

    class Foo
    {
    public:
    int bar;
    };

    int main()
    {
    HeapManager::pSelf = &theHeap;
    Foo* ptr = new Foo;
    Foo* ptr2 = new Foo;
    delete ptr;
    delete ptr2;


    return 0;

    }
     
    , Dec 20, 2005
    #1
    1. Advertising

  2. mlimber Guest

    wrote:
    > Hello,
    > I'm trying to create a basic Heap manager and i have some question
    > about new/delete overloading.
    > The following code give me this output :
    > >> $./heap
    > >> registered : 0x804d098
    > >> 0x804d008 _Delete unknown block
    > >> registered : 0x804d138
    > >> 0x804d008 _Delete unknown block
    > >> 0x804d098 _Delete ok
    > >> 0x804d0a8 _Delete unknown block
    > >> 0x804d138 _Delete ok
    > >> 0x804d148 _Delete unknown block

    >
    > Why is the HeapManager::_Delete called to delete objects that weren't
    > created using HeapManager::_New ?
    > The only reason I see is that these calls come from my BlocksMap
    > internals. Is it possible to differenciate delete used by the libstdc++
    > and delete used by the parts of my programs which are after the
    > overloading ?
    > Thanks for any advice :)
    > Silver
    >
    > ------------------------------------------------
    > #include <map>
    > #include <vector>
    > #include <stdlib.h>
    > #include <string>
    > #include <string.h>
    > #include <iostream>
    >
    > using namespace std;
    >
    > class HeapManager
    > {
    > public:
    > struct BlockDescriptor {
    > size_t size;
    > char filename[100];
    > int line;
    > };
    > static HeapManager* pSelf;
    > ~HeapManager ();
    > void* _New (size_t size, const string& filename, int line);
    > void _Delete (void* addr);
    > private:
    > typedef map<void*, BlockDescriptor*> t_blocksMap;
    > t_blocksMap BlocksMap;
    > };
    >
    > HeapManager::~HeapManager ()
    > {
    > vector<t_blocksMap::iterator> toErase;
    > t_blocksMap::iterator i;
    > for(i=BlocksMap.begin(); i!=BlocksMap.end(); i++) {
    > cout << "leak : " << i->second->filename << ":" << i->second->line
    > <<endl;
    > free(i->second);
    > free(i->first);
    > toErase.push_back(i);
    > }
    > for(unsigned int j =0; j<toErase.size(); j++) {
    > BlocksMap.erase(toErase[j]);
    > }
    > }
    >
    > void* HeapManager::_New(size_t size, const string& filename, int line)
    > {
    > if(size <= 0)
    > return 0;
    >
    > BlockDescriptor* pDesc =
    > (BlockDescriptor*)malloc(sizeof(BlockDescriptor));
    > pDesc->size = size;
    > strncpy(pDesc->filename,filename.data(),99);
    > pDesc->filename[99] = '\0';
    > pDesc->line = line;
    > void* block = malloc(size);
    > BlocksMap.insert(make_pair(block,pDesc));
    > cout << "registered : " << block << endl;
    > return block;
    > }
    >
    > void HeapManager::_Delete(void* addr)
    > {
    > if(addr == 0)
    > return;
    > cout << addr << " ";
    > t_blocksMap::iterator i = BlocksMap.find(addr);
    > if (i != BlocksMap.end()) {
    > cout << "_Delete ok " << endl;
    > free(i->second);
    > BlocksMap.erase(i);
    > } else {
    > cout << "_Delete unknown block" << endl;
    > }
    > free(addr);
    > }
    >
    > void* operator new(size_t size, const string& filename, int line) {
    > return HeapManager::pSelf->_New(size, filename, line);
    > }
    >
    > void* operator new[](size_t size, const string& filename, int line) {
    > return HeapManager::pSelf->_New(size, filename, line);
    > }
    >
    > void operator delete (void* addr) {
    > HeapManager::pSelf->_Delete(addr);
    > }
    >
    > void operator delete [] (void* addr) {
    > HeapManager::pSelf->_Delete(addr);
    > }
    >
    > #define new new(__FILE__,__LINE__)
    >
    > HeapManager* HeapManager::pSelf = NULL;
    > HeapManager theHeap;
    >
    > class Foo
    > {
    > public:
    > int bar;
    > };
    >
    > int main()
    > {
    > HeapManager::pSelf = &theHeap;
    > Foo* ptr = new Foo;
    > Foo* ptr2 = new Foo;
    > delete ptr;
    > delete ptr2;
    >
    >
    > return 0;
    >
    > }


    First of all, symbols such as _New and _Delete are illegitimate. All
    symbols beginning with an underscore and captial letter are reserved
    for use by the implementation. Fix that, try it again to make sure it's
    not an implementation conflict, and then we can talk.

    Second, you might be interested in this FAQ that discusses overloading
    new and delete:

    http://www.parashift.com/c -faq-lite/dtors.html#faq-11.14

    Third, you might consider using the singleton pattern for your heap
    manager rather than that pointer to self trick. See _Modern C++ Design_
    chapter 6 for more than you ever wanted to know about C++ singletons.

    Cheers! --M
     
    mlimber, Dec 20, 2005
    #2
    1. Advertising

  3. Guest

    Thanks for your answers.

    >From what i learnt from the FAQ, if i want that only the objects

    created through my new(size_t, const string&, int) call my overloaded
    delete, i must redefine delete(void*, const string& , int ).

    I rewrote my code with Singleton and correct symbols, but if i redefine
    delete(void*, const string&, int), the program crash in dbgheap.c:1252
    (_CrtIsValidHeapPointer). If i comment my 'new' delete an keep the old
    delete(void*), i get the same output than in the first message.

    Silver

    ----------------
    // heap.cpp : Defines the entry point for the console application.
    //

    #include "stdafx.h"

    #include <map>
    #include <vector>
    #include <stdlib.h>
    #include <string>
    #include <string.h>
    #include <iostream>

    using namespace std;

    class HeapManager
    {
    public:
    struct BlockDescriptor {
    size_t size;
    char filename[100];
    int line;
    };
    static HeapManager* Instance();

    void* myNew (size_t size, const string& filename, int line);
    void myDelete (void* addr);
    private:
    typedef map<void*, BlockDescriptor*> t_blocksMap;
    t_blocksMap BlocksMap;
    HeapManager();
    HeapManager(const HeapManager&);
    HeapManager& operator= (const HeapManager&);
    ~HeapManager ();
    };

    HeapManager::HeapManager()
    {

    }

    HeapManager::HeapManager(const HeapManager&)
    {

    }

    HeapManager& HeapManager::eek:perator = (const HeapManager&)
    {
    return *Instance();
    }

    HeapManager* HeapManager::Instance()
    {
    static HeapManager inst;
    return &inst;
    }

    HeapManager::~HeapManager ()
    {
    vector<t_blocksMap::iterator> toErase;
    t_blocksMap::iterator i;
    for(i=BlocksMap.begin(); i!=BlocksMap.end(); i++) {
    cout << "leak : " << i->second->filename << ":" << i->second->line
    <<endl;
    free(i->second);
    free(i->first);
    toErase.push_back(i);
    }
    for(unsigned int j =0; j<toErase.size(); j++) {
    BlocksMap.erase(toErase[j]);
    }
    }

    void* HeapManager::myNew(size_t size, const string& filename, int line)
    {
    if(size <= 0)
    return 0;

    BlockDescriptor* pDesc =
    (BlockDescriptor*)malloc(sizeof(BlockDescriptor));
    pDesc->size = size;
    strncpy(pDesc->filename,filename.data(),99);
    pDesc->filename[99] = '\0';
    pDesc->line = line;
    void* block = malloc(size);
    BlocksMap.insert(make_pair(block,pDesc));
    cout << "registered : " << block << endl;
    return block;
    }

    void HeapManager::myDelete(void* addr)
    {
    if(addr == 0)
    return;
    cout << addr << " ";
    t_blocksMap::iterator i = BlocksMap.find(addr);
    if (i != BlocksMap.end()) {
    cout << "_Delete ok " << endl;
    free(i->second);
    BlocksMap.erase(i);
    } else {
    cout << "_Delete unregistered" << endl;
    }
    free(addr);
    }

    void* operator new(size_t size, const string& filename, int line) {
    return HeapManager::Instance()->myNew(size, filename, line);
    }

    void* operator new[](size_t size, const string& filename, int line) {
    return HeapManager::Instance()->myNew(size, filename, line);
    }

    void operator delete(void* addr, const string& filename, int line) {
    HeapManager::Instance()->myDelete(addr);
    }

    void operator delete[](void* addr, const string& filename, int line){
    HeapManager::Instance()->myDelete(addr);
    }
    /*
    void operator delete (void* addr) {
    HeapManager::Instance()->myDelete(addr);
    }

    void operator delete [] (void* addr) {
    HeapManager::Instance()->myDelete(addr);
    }*/

    #define new new(__FILE__,__LINE__)



    class Foo
    {
    public:
    int bar;
    };

    int main()
    {
    Foo* ptr = new Foo;
    Foo* ptr2 = new Foo;
    delete ptr;
    delete ptr2;


    return 0;

    }
     
    , Dec 21, 2005
    #3
  4. mlimber Guest

    wrote:
    > Thanks for your answers.
    >
    > >From what i learnt from the FAQ, if i want that only the objects

    > created through my new(size_t, const string&, int) call my overloaded
    > delete, i must redefine delete(void*, const string& , int ).


    Yes, you must do this for exception safety. See the FAQ.

    >
    > I rewrote my code with Singleton and correct symbols, but if i redefine
    > delete(void*, const string&, int), the program crash in dbgheap.c:1252
    > (_CrtIsValidHeapPointer). If i comment my 'new' delete an keep the old
    > delete(void*), i get the same output than in the first message.


    You must not do this. See below.

    >
    > Silver
    >
    > ----------------
    > // heap.cpp : Defines the entry point for the console application.
    > //
    >
    > #include "stdafx.h"
    >
    > #include <map>
    > #include <vector>
    > #include <stdlib.h>


    Prefer <cstdlib>

    > #include <string>
    > #include <string.h>


    Prefer <cstring>

    > #include <iostream>
    >
    > using namespace std;
    >
    > class HeapManager
    > {
    > public:
    > struct BlockDescriptor {
    > size_t size;
    > char filename[100];
    > int line;
    > };
    > static HeapManager* Instance();
    >
    > void* myNew (size_t size, const string& filename, int line);
    > void myDelete (void* addr);
    > private:
    > typedef map<void*, BlockDescriptor*> t_blocksMap;
    > t_blocksMap BlocksMap;
    > HeapManager();
    > HeapManager(const HeapManager&);
    > HeapManager& operator= (const HeapManager&);
    > ~HeapManager ();
    > };
    >
    > HeapManager::HeapManager()
    > {
    >
    > }
    >
    > HeapManager::HeapManager(const HeapManager&)
    > {
    >
    > }
    >
    > HeapManager& HeapManager::eek:perator = (const HeapManager&)
    > {
    > return *Instance();
    > }
    >
    > HeapManager* HeapManager::Instance()
    > {
    > static HeapManager inst;
    > return &inst;
    > }
    >
    > HeapManager::~HeapManager ()
    > {
    > vector<t_blocksMap::iterator> toErase;
    > t_blocksMap::iterator i;
    > for(i=BlocksMap.begin(); i!=BlocksMap.end(); i++) {
    > cout << "leak : " << i->second->filename << ":" << i->second->line
    > <<endl;
    > free(i->second);
    > free(i->first);
    > toErase.push_back(i);
    > }
    > for(unsigned int j =0; j<toErase.size(); j++) {
    > BlocksMap.erase(toErase[j]);
    > }
    > }
    >
    > void* HeapManager::myNew(size_t size, const string& filename, int line)
    > {
    > if(size <= 0)
    > return 0;
    >
    > BlockDescriptor* pDesc =
    > (BlockDescriptor*)malloc(sizeof(BlockDescriptor));
    > pDesc->size = size;
    > strncpy(pDesc->filename,filename.data(),99);
    > pDesc->filename[99] = '\0';
    > pDesc->line = line;
    > void* block = malloc(size);
    > BlocksMap.insert(make_pair(block,pDesc));
    > cout << "registered : " << block << endl;
    > return block;
    > }
    >
    > void HeapManager::myDelete(void* addr)
    > {
    > if(addr == 0)
    > return;
    > cout << addr << " ";
    > t_blocksMap::iterator i = BlocksMap.find(addr);
    > if (i != BlocksMap.end()) {
    > cout << "_Delete ok " << endl;
    > free(i->second);
    > BlocksMap.erase(i);
    > } else {
    > cout << "_Delete unregistered" << endl;
    > }
    > free(addr);
    > }
    >
    > void* operator new(size_t size, const string& filename, int line) {
    > return HeapManager::Instance()->myNew(size, filename, line);
    > }
    >
    > void* operator new[](size_t size, const string& filename, int line) {
    > return HeapManager::Instance()->myNew(size, filename, line);
    > }
    >
    > void operator delete(void* addr, const string& filename, int line) {
    > HeapManager::Instance()->myDelete(addr);
    > }
    >
    > void operator delete[](void* addr, const string& filename, int line){
    > HeapManager::Instance()->myDelete(addr);
    > }
    > /*
    > void operator delete (void* addr) {
    > HeapManager::Instance()->myDelete(addr);
    > }
    >
    > void operator delete [] (void* addr) {
    > HeapManager::Instance()->myDelete(addr);
    > }*/
    >
    > #define new new(__FILE__,__LINE__)


    Get rid of this macro. See below.

    >
    >
    >
    > class Foo
    > {
    > public:
    > int bar;
    > };
    >
    > int main()
    > {
    > Foo* ptr = new Foo;
    > Foo* ptr2 = new Foo;
    > delete ptr;
    > delete ptr2;
    >
    >
    > return 0;
    >
    > }


    First, regarding the singleton, I'd suggest something along these
    lines, though perhaps you need something even more sophisticated in
    terms of lifetime management (for which, see _Modern C++ Design_):

    template<class T>
    class Singleton
    {
    public:
    static T& Instance();
    private:
    // Disabled functions
    Singleton();
    Singleton( const Singleton& );
    Singleton& operator=( const Singleton& );
    Singleton* operator&();
    ~Singleton();
    };

    template<class T>
    T& Singleton<T>::Instance()
    {
    static T myObject;
    return myObject;
    }


    class HeapManager
    {
    // Private ctor/dtor accessible only to friends
    friend class Singleton<HeapManager>;
    HeapManager() { /* ... */ }
    ~HeapManager() { /* ... */ }

    // Disabled functions for singleton usage
    HeapManager( const HeapManager& );
    HeapManager& operator=( const HeapManager& );
    HeapManager* operator&();

    // ...

    public:
    // ...
    };

    typedef Singleton<HeapManager> theHeapManager;

    Second, regarding the questions from your previous post:

    > >> registered : 0x804d098
    > >> 0x804d008 _Delete unknown block
    > >> registered : 0x804d138
    > >> 0x804d008 _Delete unknown block
    > >> 0x804d098 _Delete ok
    > >> 0x804d0a8 _Delete unknown block
    > >> 0x804d138 _Delete ok
    > >> 0x804d148 _Delete unknown block

    >
    > Why is the HeapManager::_Delete called to delete objects that weren't
    > created using HeapManager::_New ?


    Because in your original code you overload the *global* new and delete
    operators. Consequently, your delete operator is being called from
    std::string, but your new operator wasn't called from std::string
    because the function signatures didn't match and your "#define new"
    wasn't in effect yet.

    In your updated code, you (rightly) provide a matching delete operator
    for your new operator, but you incorrectly invoke the global (i.e., not
    your own) delete operator in main(). Also, your updated code won't work
    since the file and line numbers must be identical to match your map's
    key. With your current operators, you'd need to do something like this
    (assuming you get rid of the macro):

    Foo* ptr = new("Bob",1) Foo;
    Foo* ptr2 = new("Joe",2) Foo;
    operator delete(ptr, "Bob",1); // same parameters as above!
    operator delete(ptr2, "Joe",2); // same parameters as above!

    You'll probably want to change to some other key type than a string/int
    pair since the filename/line number thing won't work. In order to get
    rid of the ugly syntax in this code, I'll refer you to that same FAQ
    again. It describes in detail how to create a custom new/delete pair
    and then how to overload the gloabal new/delete operators to use them.

    http://www.parashift.com/c -faq-lite/dtors.html#faq-11.14

    If you don't understand the FAQ, ask some specific questions. I'm sure
    someone here can help.

    Cheers! --M
     
    mlimber, Dec 21, 2005
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. HeroOfSpielburg
    Replies:
    1
    Views:
    394
    Alf P. Steinbach
    Aug 6, 2003
  2. Jef Driesen
    Replies:
    1
    Views:
    506
    Gernot Frisch
    Jan 19, 2005
  3. Michal Slocinski

    Heap dump file size vs heap size

    Michal Slocinski, Mar 25, 2008, in forum: Java
    Replies:
    1
    Views:
    739
    GArlington
    Mar 25, 2008
  4. viki
    Replies:
    6
    Views:
    566
    Erik Wikström
    Jun 28, 2008
  5. Raymond Schanks
    Replies:
    0
    Views:
    538
    Raymond Schanks
    Apr 11, 2010
Loading...

Share This Page