Jump to content


STL - Vice & Virtues


4 replies to this topic

#1 Mario

    New Member

  • Members
  • Pip
  • 5 posts

Posted 05 November 2004 - 09:03 PM

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 ?

#2 Michael

    Member

  • Members
  • PipPip
  • 67 posts

Posted 05 November 2004 - 10:13 PM

Mario said:

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.

#3 Reedbeta

    DevMaster Staff

  • Administrators
  • 5307 posts
  • LocationBellevue, WA

Posted 05 November 2004 - 11:53 PM

Yeah, the STL is definetly supposed to call all the proper constructors and destructors. Perhaps you had a shoddy implementation?
reedbeta.com - developer blog, OpenGL demos, and other projects

#4 bladder

    DevMaster Staff

  • Members
  • PipPipPipPip
  • 1057 posts

Posted 06 November 2004 - 12:01 AM

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.

#5 NomadRock

    Senior Member

  • Members
  • PipPipPipPip
  • 785 posts

Posted 06 November 2004 - 08:49 PM

Try using STLPort
Jesse Coyle





1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users