Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » std::auto_ptr and std::list

This thread is locked; no one can reply to it. rss feed Print
std::auto_ptr and std::list
Martin Kalbfuß
Member #9,131
October 2007
avatar

I want to store some object in an list. But poymorphism is needed. So I have to work with references. To avoid any memory leaks. I tried to use std::auto_ptr.

My container is:

class Layer : public GameObj, public std::list< std::auto_ptr<GameObj> >
{
  public:

  virtual void draw();
  virtual void update();      
};

And this is where I try to create my str::auto_ptr and add it to the list:

OperationRaubvogel::OperationRaubvogel() : Game(320, 240, 0)
{
  useKeyboard();
  useTheme("sprites.png");
  
  std::auto_ptr<GameObj> ship( new Ship );
  push_back(ship);
}

I get a long list of errors, pointing inside the stdlib. I'm new to the topic and have no idea how to go on.

Some additional infos:

OperationRaubvogel is a Game which is a Layer.
Ship is a GameObj.

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

X-G
Member #856
December 2000
avatar

Never put auto_ptrs in a container. Never, ever, ever. Why? Because auto_ptr does not have proper copy semantics and will be freed almost immediately.

Use boost::shared_ptr instead.

EDIT: In fact, don't use auto_ptr for anything. It's too easy to screw up. Use boost::shared_ptr or boost::scoped_ptr, depending on what you're doing.

EDIT2: Also, don't inherit from std::list.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Martin Kalbfuß
Member #9,131
October 2007
avatar

My head hurts :-/ . Isn't there a way without an additional lib?

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

X-G
Member #856
December 2000
avatar

No. Besides, if you're serious about C++, you should get boost anyway. shared_ptr is header-only, so you don't need to worry about compiling anything. Just include and go.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

anonymous
Member #8025
November 2006

Isn't there a way without an additional lib?

If you have recent compiler, then you might also have std::tr1::shared_ptr. With GCC 4.4 it is already std::shared_ptr in <memory>.

Martin Kalbfuß
Member #9,131
October 2007
avatar

I have 4.3 :P. Is this standard C++?

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

anonymous
Member #8025
November 2006

shared_ptr is an addition to the standard library with C++0x.

Thomas Fjellstrom
Member #476
June 2000
avatar

anonymous said:

shared_ptr is an addition to the standard library with C++0x.

I think you mean C++1x.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Martin Kalbfuß
Member #9,131
October 2007
avatar

So it's going to be standard. Boost I'm comming.

:o Do you think it takes so long?

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

gnolam
Member #2,030
March 2002
avatar

anonymous said:

shared_ptr is an addition to the standard library with C++0x.

I think you mean C++1x.

There's still plenty of time for a finalization of C++0x: C++0a, C++0b, C++0c... ;)

--
Move to the Democratic People's Republic of Vivendi Universal (formerly known as Sweden) - officially democracy- and privacy-free since 2008-06-18!

Thomas Fjellstrom
Member #476
June 2000
avatar

Do you think it takes so long?

It's been postponed till at least 2010.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Martin Kalbfuß
Member #9,131
October 2007
avatar

I still don't understand why it's bad to inherit from standard containers directly.

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

X-G
Member #856
December 2000
avatar

Is-a vs. has-a. Your Layer is not a list of objects, it HAS a list of objects.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Martin Kalbfuß
Member #9,131
October 2007
avatar

So it is a design question? No technical problems?

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

X-G
Member #856
December 2000
avatar

Don't underestimate design issues. Two things come immediately to mind:

  • You're also giving outside objects internal access to every object in the list -- they can delete and move around objects outside of the Layer's control, swap and erase, etc. all without proper or indeed any encapsulation.

  • As your class grows in functionality, you might want to add more stuff to the Layer -- another list of objects, perhaps -- and now you're in a really bloody weird spot, aren't you, with a list-in-a-list. Xzibit would be proud, but I won't.

EDIT: There is another very good reason you should consider in this particular case: standard containers do not have virtual destructors, but that class has virtual methods and so it must -- meaning you're opening yourself up for really unpredictable (undefined, actually) memory errors.

Here, you are even further complicating the issue by doing virtual multiple inheritance, which is honestly a mess that I only barely understand properly.

In the end, you have no reason to do this and it's both technically and design-wise a tremendously bad idea. Don't do it. I'd hate to phrase it this way, but if it helps to convince you, then: please, take it from someone who actually works in the industry with C++ on a daily basis. This is not a good idea.

--
Since 2008-Jun-18, democracy in Sweden is dead. | 悪霊退散!悪霊退散!怨霊、物の怪、困った時は ドーマン!セーマン!ドーマン!セーマン! 直ぐに呼びましょう陰陽師レッツゴー!

Martin Kalbfuß
Member #9,131
October 2007
avatar

I will change it. But at the moment I'm too lazy. It was too easy to to be correct :-/. Programming can be really annoying sometimes. It's always more difficult then it seems.

One thing interests me. When I would add a virtual destructor to my layer class. Shouldn't this solve memory problems, except for referencing objects a std::list what I wouldn't do, anyway.

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

gillius
Member #119
April 2000

You should always have a virtual destructor if you think that the class has a possibility of being subclassed, and used as a pointer to your class (the parent). Considering that you can't really control the situation, sometimes programmers give every exposed class a virtual destructor.

The consequence of not doing this is that if your object is used on a polymorphic situation, your destructor may not be called when the object is destroyed, which is a bad plan. The consequence of having a virtual destructor when you don't need it is the cost of probably 4 bytes/object for a vtable pointer (and possibly none extra if RTTI is enabled).

Gillius
Gillius's Programming -- https://gillius.org/

Timorg
Member #2,028
March 2002

I can't remember where I got this from but you don't have to install boost if you want a smart pointer.

I have used this reference count pointer quite a bit, and it does the job.

#SelectExpand
1/* 2 * counted_ptr - simple reference counted pointer. 3 * 4 * The is a non-intrusive implementation that allocates an additional 5 * int and pointer for every counted object. 6 */ 7 8#ifndef COUNTED_PTR_H 9#define COUNTED_PTR_H 10 11/* For ANSI-challenged compilers, you may want to #define 12 * NO_MEMBER_TEMPLATES or explicit */ 13 14#define NO_MEMBER_TEMPLATES 15 16template <class X> class counted_ptr 17{ 18public: 19 typedef X element_type; 20 21 explicit counted_ptr(X* p = 0) // allocate a new counter 22 : itsCounter(0) {if (p) itsCounter = new counter(p);} 23 ~counted_ptr() 24 {release();} 25 counted_ptr(const counted_ptr& r) throw() 26 {acquire(r.itsCounter);} 27 counted_ptr& operator=(const counted_ptr& r) 28 { 29 if (this != &r) { 30 release(); 31 acquire(r.itsCounter); 32 } 33 return *this; 34 } 35 36 // timmy added 37 bool operator==(const counted_ptr<X> c) const 38 { 39 return (get() == c.get()); 40 } 41 bool operator!=(const counted_ptr<X> c) const 42 { 43 return (get() != c.get()); 44 } // timmy added end 45 46#ifndef NO_MEMBER_TEMPLATES 47 template <class Y> friend class counted_ptr<Y>; 48 template <class Y> counted_ptr(const counted_ptr<Y>& r) throw() 49 {acquire(r.itsCounter);} 50 template <class Y> counted_ptr& operator=(const counted_ptr<Y>& r) 51 { 52 if (this != &r) { 53 release(); 54 acquire(r.itsCounter); 55 } 56 return *this; 57 } 58#endif // NO_MEMBER_TEMPLATES 59 60 X& operator*() const throw() {return *itsCounter->ptr;} 61 X* operator->() const throw() {return itsCounter->ptr;} 62 X* get() const throw() {return itsCounter ? itsCounter->ptr : 0;} 63 bool unique() const throw() 64 {return (itsCounter ? itsCounter->count == 1 : true);} 65 66private: 67 68 struct counter { 69 counter(X* p = 0, unsigned c = 1) : ptr(p), count(c) {} 70 X* ptr; 71 unsigned count; 72 }* itsCounter; 73 74 void acquire(counter* c) throw() 75 { // increment the count 76 itsCounter = c; 77 if (c) ++c->count; 78 } 79 80 void release() 81 { // decrement the count, delete if it is 0 82 if (itsCounter) { 83 if (--itsCounter->count == 0) { 84 delete itsCounter->ptr; 85 delete itsCounter; 86 } 87 itsCounter = 0; 88 } 89 } 90}; 91 92#endif // COUNTED_PTR_H

Edit:
It came from here.

____________________________________________________________________________________________
"c is much better than c++ if you don't need OOP simply because it's smaller and requires less load time." - alethiophile
OMG my sides are hurting from laughing so hard... :D

gillius
Member #119
April 2000

smart pointers are notoriously difficult to get right (and perform well). Peter Dimov and others worked for some years on boost shared_ptr to get it right in the face of exceptions and threads, and weak_ptr as well.

Scanning that class above quickly for certain constructs, it doesn't seem to handle the exceptions. I'm not sure about out-of-memory conditions. So, if your code doesn't use threads or exceptions it will probably work perfectly.

I suppose my point is, using shared_ptr is the best way to go if you can, but this counted_ptr is probably good enough for something small and not for "production," and you don't need features like weak_ptr.

Gillius
Gillius's Programming -- https://gillius.org/

Martin Kalbfuß
Member #9,131
October 2007
avatar

I decided to use boost. Thanks.

http://remote-lisp.spdns.de -- my server side lisp interpreter
http://www.nongnu.org/gm2/ -- Modula-2 alias Pascal++

GullRaDriel
Member #3,861
September 2003
avatar

C++ just sucks because of these silly design questions. /arse ;D

"Code is like shit - it only smells if it is not yours"
Allegro Wiki, full of examples and articles !!

Go to: