![]() |
|
std::auto_ptr and std::list |
Martin Kalbfuß
Member #9,131
October 2007
![]() |
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. http://remote-lisp.spdns.de -- my server side lisp interpreter |
X-G
Member #856
December 2000
![]() |
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. -- |
Martin Kalbfuß
Member #9,131
October 2007
![]() |
My head hurts http://remote-lisp.spdns.de -- my server side lisp interpreter |
X-G
Member #856
December 2000
![]() |
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. -- |
anonymous
Member #8025
November 2006
|
Martin Kalbfuß said: 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
![]() |
I have 4.3 http://remote-lisp.spdns.de -- my server side lisp interpreter |
anonymous
Member #8025
November 2006
|
shared_ptr is an addition to the standard library with C++0x. |
Thomas Fjellstrom
Member #476
June 2000
![]() |
anonymous said: shared_ptr is an addition to the standard library with C++0x. I think you mean C++1x. -- |
Martin Kalbfuß
Member #9,131
October 2007
![]() |
So it's going to be standard. Boost I'm comming.
http://remote-lisp.spdns.de -- my server side lisp interpreter |
gnolam
Member #2,030
March 2002
![]() |
Thomas Fjellstrom said: 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... -- |
Thomas Fjellstrom
Member #476
June 2000
![]() |
Martin Kalbfuß said: Do you think it takes so long? It's been postponed till at least 2010. -- |
Martin Kalbfuß
Member #9,131
October 2007
![]() |
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 |
X-G
Member #856
December 2000
![]() |
Is-a vs. has-a. Your Layer is not a list of objects, it HAS a list of objects. -- |
Martin Kalbfuß
Member #9,131
October 2007
![]() |
So it is a design question? No technical problems? http://remote-lisp.spdns.de -- my server side lisp interpreter |
X-G
Member #856
December 2000
![]() |
Don't underestimate design issues. Two things come immediately to mind:
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. -- |
Martin Kalbfuß
Member #9,131
October 2007
![]() |
I will change it. But at the moment I'm too lazy. It was too easy to to be correct 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 |
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 |
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. 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: ____________________________________________________________________________________________ |
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 |
Martin Kalbfuß
Member #9,131
October 2007
![]() |
I decided to use boost. Thanks. http://remote-lisp.spdns.de -- my server side lisp interpreter |
GullRaDriel
Member #3,861
September 2003
![]() |
C++ just sucks because of these silly design questions. /arse "Code is like shit - it only smells if it is not yours" |
|