STL - Vice & Virtues

2b745549fe339c54b768543c9faa96ea
0
Mario 101 Nov 05, 2004 at 21:03

Over a year ago, during the work on the various resource managers, I was unpleasantly startled by the behaviour of STL containers. To present how does the matter of problem stand, it would be the best to include some piece of code:

class Clonable 
{ 
 public: 
  virtual ~Clonable (); 
  virtual Clonable* clone () const; // Virtual constructor 
}; 

class Referable : public Clonable 
{ 
 private: 
  int nref; // Reference counter 
  ...
 public: 
  ... 
  virtual ~Referable (); 
  virtual Referable* clone () const; 
  ... 
  template<typename T> friend class SmartPtr; 
}; 

template<typename T> // T must be the type of public Referable class 
class SmartPtr 
{ 
 public: 
  ... 
  SmartPtr (const SmartPtr<T>& sp); // Copy constructor 
  ... 
  SmartPtr<T>& operator= (const SmartPtr<T>& sp); // Assigment operator 
  ... 
}; 

As it is seen, the code above defines the invasive smart pointer class and pointer-base class, which derivates could be referred by SmartPtr. It’s needless to say, that SmartPtr methods do little more than a simple assigment, whereas it operates on reference counter. Thus the proper work of SmartPtr class and it’s references is sustained only by the usage of class’ internal methods.
This code should work correctly:

class Actor : public Referable 
{ 
 ... 
 public: 
  void play (); 
} 
... 
int main (int argc, char* argv[]) 
{ 
 SmartPtr<Actor> p1(new Actor(...)), p2(new Actor(...)); 
 p2 = p1; 
 p1.release(); 
 p2->play(); 
 p2->release(); 
 // No memory leaks 
 ... 
} 

It would be fine if I could create a deque (or vector, list, map or even AVL tree) of smart pointers; unfortunately the followind code doesn’t work correctly:

... 
std::deque<SmartPtr<Actor> > actors; 
actors.push_back(new Actor(...)); // Implicit conversion from Actor* to SmartPtr<Actor> is supported by SmartPtr<T>::SmartPtr(T*) 
... 
actors.clear(); // Does not call virtual destructor Actor::~Actor, so actor's nref will never reach 0 and object won't be destroyed 
// Memory heap still contains object Actor 

The implementation of std::deque (and other containers) uses memcpy() function instead of operator= method and copy constructor (I’ve checked VC++ 6.0 and portable-STL implementations). I ommit those circumstances by implementing a disting class SmartPtrDeque, but it’s not a solution (which seems proper).

So my question is: Is it possible to force STL containers to treat it’s data as objects, not structures ?

4 Replies

Please log in or register to post a reply.

40d3c1d8f291e5f90cc05985e00da115
0
Michael 101 Nov 05, 2004 at 22:13

@Mario

The implementation of std::deque (and other containers) uses memcpy() function instead of operator= method and copy constructor

I couldn’t find uses of memcpy - but for construction they often use one large allocation and in-place construction, and for destruction they explicitely call the destructor, so there shouldn’t be any issues.

A8433b04cb41dd57113740b779f61acb
0
Reedbeta 168 Nov 05, 2004 at 23:53

Yeah, the STL is definetly supposed to call all the proper constructors and destructors. Perhaps you had a shoddy implementation?

22b3033832c5c699c856814b0cf80cb1
0
bladder 101 Nov 06, 2004 at 00:01

Yeah, what Michael said. The stl with vc6 is horribly buggy though. Try using another smart pointer class - like boost::shared_pointer (http://www.boost.org) and see if it works with that. If it does, then you got problems in your SmartPtr implementation.

7543b5c50738e23b200e69fe697ea85a
0
NomadRock 101 Nov 06, 2004 at 20:49

Try using STLPort