views:

92

answers:

3

To implement reference counting we use an IUnknown-like interface and a smart pointer template class. The interface has implementation for all the reference-count methods, including Release():

void IUnknownLike::Release()
{
   if( --refCount == 0 ) {
       delete this;
   }
}

The smart pointer template class has a copy constructor and an assignment operator both accepting raw pointers. So users can do the following:

 class Class : public IUnknownLike {
 };

 void someFunction( CSmartPointer<Class> object ); //whatever function
 Class object;
 someFunction( &object );

and the program runs into undefined behavior - the object is created with reference count zero, the smart pointer is constructed and bumps it to one, then the function returns, smart pointer is destroyed, calls Release() which leads to delete of a stack-allocated variable.

Users can as well do the following:

struct COuter {
    //whatever else;
    Class inner;// IUnknownLike descendant
};
COuter object;
somefunction( &object.Inner );

and again an object not created with new is deleted. Undefined behavior at its best.

Is there any way to change the IUnknownLike interface so that the user is forced to use new for creating all objects derived from IUnknownLike - both directly derived and indirectly derived (with classes in between the most derived and the base)?

+1  A: 

Make the constructor private and write a static member function that uses new

class IUnknownLike{
public:
  static IUnknownLike * createIUnknownLike(); { return new IUnknownLike(); }

private:
  IUnknownLike (); // private ctor
};

IUnknownLike* obj = createIUnknownLike();
Draco Ater
I need to derive 100500 classes from the interface. How do I proceed?
sharptooth
Chances are that if you are deriving so many classes you will probably automate the generation of the classes :)
David Rodríguez - dribeas
+1  A: 

You can make the Base class's destructor protected and smart pointer class his friend.

Thus the users will be unable to create the instance of the class on stack. They'll have to use operator new and smart_pointer class, that will call release and delete.

Dmitry Yudakov
We already have that. The problem is noone creates the Base on stack. They derive from base first and that's why having Base destructor protected doesn't help.
sharptooth
A: 

If you're really intent on doing this for so many classes, use a macro to create the factory method. Something like:

#define FACTORY(NAME) protected: NAME();\
public: static NAME* create ## NAME(){ return new NAME(); }

If you want to pass parameters to the constructors, you'll have to get fancier.

The alternative is to implement the rest of COM and have each class register a factory function with a central object creation system. While an interesting exercise, this all sounds like a terrible idea.

Alex
This in fact prohibits using constructors with parameters and it is very unfortunate.
sharptooth