1

I need singleton with a application lifetime, guaranteed creation/destruction and static access to it.

#include <iostream>
#include <cstdlib>

#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
    TypeName(const TypeName&);             \
    void operator=(const TypeName&)

#define M() C::sM()
#define M2() C::sM2()

using namespace std;

class C {
  private:
    static C* s;

    ~C() { cout << "~C()" << endl; }
    static C* instance() { 
        if (s==NULL) { s=new C(); }
        cout << "instance()=" << s << endl; return s; 
    }
    static void cleanUp() { delete s; }
    void m() { cout << "m()" << endl; }
    void m2() { cout << "m2()" << endl; }
    DISALLOW_COPY_AND_ASSIGN(C);
  public:
    C() { 
        cout << "C()" << endl; if (s==NULL) { 
            s=this; atexit(&cleanUp); 
            cout << "cleanUp is installed" << endl; 
        } else { 
            cout << "cleanUp is not installed" << endl; 
        } 
    }
    void* operator new(size_t sz) { 
        void* p=NULL; if (s==NULL) { p=new char[sz]; } else { p=s; }
        cout << "new(" << sz << ")=" << p << endl;
        return p;
    }
    void operator delete(void* p, size_t sz) { 
        cout << "delete(" << sz << "," << p << ")" << endl;
        if (p) delete[] static_cast<char*>(p); s=NULL; 
    }
    void static sM() { cout << "sM()" << endl; instance()->m(); }
    void static sM2() { cout << "sM2()" << endl; instance()->m2(); }
};

C* C::s = NULL;

int main() {
    M();
    M2();
    C* p1 = new C();
    C* p2 = new C();
}  

But I don't know how to get rid of g++ warning:

test.cpp: In static member function 'static void C::operator delete(void*, size_t)':
test.cpp:22: warning: deleting 'void*' is undefined

If I write C* instead of void*, destructor start calling itself in infinite loop. Can anybody help me to get clean code without warnings? C++98 of course.

Dmitry
  • 33
  • 1
  • 6

4 Answers4

4

The way I'm used to write singletons (whenever I really need one) is:

class Singleton
{
public:
     static Singleton& instance()
     {
          static Singleton theInstance;
          return theInstance;
     }

private:
     Singleton()
     {
     }
};

No need to mess around with overloading new and delete.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • I think the OP has overloaded the operators as he wants to log every call to `new` and `delete`. – Felix Glas Sep 04 '13 at 12:38
  • 1
    @Snps Logging it in the con/destructor would be a better option. – Bernhard Barker Sep 04 '13 at 12:40
  • @Dukeling Agreed, except for built in types. – Felix Glas Sep 04 '13 at 12:43
  • @Dmitry That should be called when? `_atexit()` ? Simply register a friend function or s.th. like this. The instance's lifetime management will depend on how `crt0` is actually implemented (some implementations might not call `delete`for the singleton at all. – πάντα ῥεῖ Sep 04 '13 at 12:48
  • @g-makulik I've read a chapter about singletons in C++ in "Modern C++ design" by A. Alexandrescu and haven't seen other than _atexit option of destructing singleton. – Dmitry Sep 04 '13 at 12:56
  • @Dmitry `_atexit` might be fine as entry point to do the 'dirty work'. Register a friend or private static function that does it instead of using the destructor. – πάντα ῥεῖ Sep 04 '13 at 13:01
2

You do not need to overload neither new() nor delete(). And you probably do not need to hand out a pointer to your customers. A reference will do.

Construction and destruction of the singleton will be done in your instance(), which could look like so:

static C& instance() {
  static C _instance;
  cout << "instance()" << endl; 
  return _instance; 
}

This guarantees construction and destruction, because the constructor of C is called when the first user calls instance(), and only with the first call. Destruction will happen at the end of your program.

Henno
  • 397
  • 1
  • 7
  • It actually only guarantees construction (not necessarily destruction) AFAIK. – πάντα ῥεῖ Sep 04 '13 at 12:54
  • It guarantees construction and destruction (_The C++ Programming Language_, Stroustrup, 2000). – Oktalist Sep 04 '13 at 13:23
  • @g_makulik I am quite sure that destruction of static objects is guaranteed to commence after `main()` has ended, in the reverse order of the construction. This may be a little late if he has to do things in the d'tor. – Henno Sep 04 '13 at 13:47
0

The type to delete is char*:

void operator delete(void* p, size_t sz) { 
    cout << "delete(" << sz << "," << p << ")" << endl;
    if (p) delete (char*) p;
}

There is a bug in your new: What's the difference between new char[10] and new char(10)

Maybe should be:

p=new char[sz];

and then

delete[] (char*)p ;

---- edited:

The delete for purists, sacrificing clarity to people learning ;P :

delete[] static_cast<char*>(p) ;

(*actually I appreciate the note about the cast)

Community
  • 1
  • 1
Alfonso Nishikawa
  • 1,876
  • 1
  • 17
  • 33
0

It looks to me like your code should work if you just remove the new and delete overloads (which I don't really see the point of, if you want to log every con/destruction, do so in the con/destructors), but the below should fix your error.

Since you assign a char* to p, casting it to char* in the delete should work, i.e. delete (char*)p;.

However, I believe p=new char(sz); is making a char with a value of sz instead of a char array of size sz. For the latter, you may want p=new char[sz]; and then delete[] p or delete[] (char*)p;.

Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
  • @Dmitry You shouldn't really edit your question with all the fixes suggested in answers. That invalidates all those answers (which could lead to them getting downvoted or deleted), and it also invalidates your question if one of those fixes fixed your problem. Apart from (in general) formatting, indentation and possibly giving a shorter example reproducing your problem, you should generally make minimal to no changes to your code, especially if you're asking about errors. You should [accept](http://stackoverflow.com/help/someone-answers) whichever answer you feel best answers your question. – Bernhard Barker Sep 04 '13 at 13:02
  • Sorry, forgot about that. The question itself is invalid then. – Dmitry Sep 04 '13 at 13:38