Add your own alternative version
Stats
281.2K views 738 downloads 71 bookmarked
Posted
17 Apr 2005
Licenced
|
Comments and Discussions
|
|
peterchen wrote:
In a way, Smart Pointers provide deterministic destruction* where classic RAII fails due to C++ scoping rules: RAII is such a wonderful "fire and forget" mechanim, because you can bind the lifetime of an object X to either a C++ scope, or to one other object.
If you return a resource from a function by smart pointer the release of the resource is not deterministic any more. The function has ended but the resource release is pending. Yes, the resource release is smoehow assured by the smart pointer, but non-deterministic.
This mechanism fails, however, if you need binding across multiple objects or scopes. Smart Pointers cover probably 80% of these scenarios naturally.
This also explains why they have to have pointer semantics: You need to access one object X from different scopes, for which you normally need pointers. So they recycle a known concept (dereferencing), to provide the same feature (access to a shared object from multiple locations)
If you use an object in many scopes you create dependencies to that object in these scopes anyway. You can create the object on the stack in the 'highest' scope and pass it to 'lower' functions without the need for a smart pointer.
Smart Pointers in C++ have a kind of neglected history, I see two reasons for that:
First, stl included auto_ptr only, the most hideous, complex, and least applicable of resource managing smart pointers.
IMO, auto_ptr is the best of the obnoxious resource managing smart pointers because it does not allocate a mostly superfluous counter object.
BTW, following are some cornerstones of the 'smart pointer waves' in the last 15 years (from my point of view):
- Daniel R. Edelson published "Smart Pointers: They're Smart, but They're Not Pointers", http://www-sor.inria.fr/publi/SPC++_usenixC++92.html[^]
- Scott Meyers analyzed smart pointers in his book and in several articles, http://www.aristeia.com/publications_frames.html[^]
- auto_ptr was introduced into the C++ Standard and acclaimed, http://www.gotw.ca/publications/using_auto_ptr_effectively.htm[^]
- smart pointers were boosted to new dimensions by boost::smart_ptr without solving the old problems, http://www.boost.org/libs/smart_ptr/smart_ptr.htm[^]
|
|
|
|
|
Roland Pibinger wrote:
If you return a resource from a function by smart pointer the release of the resource is not deterministic any more. The function has ended but the resource release is pending. Yes, the resource release is smoehow assured by the smart pointer, but non-deterministic.
First, what means "deterministic" to you?
To me, the important point is: the moment ofdestrucion depends only on the use of the very object itself, not on other factors.
Second, how do you return a managed resource from a function, if it does not yield a copy constructor?
Roland Pibinger wrote:
You can create the object on the stack in the 'highest' scope and pass it to 'lower' functions without the need for a smart pointer.
Umm... wouldn't this mean pushing the data to the outermost scope, i.e. making it global? This is at least impractical for scarce resurces, and hinders isolation of concerns.
Smart pointers are not panacea. But neither is scope-based RAII. Nor GC. I expect a good C++ developer to use RAII automatically, use smart pointers where they make sense, and be hesitant of GC in a C-based environment.
What are your problems with reference counting smart pointers?
Pandoras Gift #44: Hope. The one that keeps you on suffering. aber.. "Wie gesagt, der Scheiss is' Therapie" boost your code || Fold With Us! || sighist | doxygen
|
|
|
|
|
peterchen wrote:
First, what means "deterministic" to you?
To me, the important point is: the moment of destrucion depends only on the use of the very object itself, not on other factors.
'Deterministic' refers to the lifetime of a resurce in a unit of code, typically a function. Example:
auto_ptr<MyClass> foo();
In this case the lifetime of the returned MyClass object is not determined by foo() . By looking at foo() you don't know when the returned object is destroyed. But in
void foo2();
all resources are deterministically released at the end of foo2 (disregarding global variables and programmer errors). This concept is akin to the commit/rollback semantics known from databases.
Second, how do you return a managed resource from a function, if it does not yield a copy constructor?
I avoid it. I see functions as 'services' that do something for me and report success or error afterwards but don't bother me with resources.
Roland Pibinger wrote:
You can create the object on the stack in the 'highest' scope and pass it to 'lower' functions without the need for a smart pointer.
Umm... wouldn't this mean pushing the data to the outermost scope, i.e. making it global? This is at least impractical for scarce resurces, and hinders isolation of concerns.
... the outermost scope in which they are actually used.
What are your problems with reference counting smart pointers?
None, because I don't use them. (in general, the same as for auto_ptr plus the unnecessary dynamically allocated counter object in each r.c.s.p.)
|
|
|
|
|
Roland Pibinger wrote:
- What are your problems with reference counting smart pointers?
None, because I don't use them. (in general, the same as for auto_ptr plus the unnecessary dynamically allocated counter object in each r.c.s.p.)
Well, I think there's too much religion and very few science in this kind of answers:
I don't pretend to offend anyone, but is a matter of fact that –even if all catholic Popes still disagree about the use of condoms and of sex outside marriage- the most of self-saying "catholic people" use them and have sex before marriage.
The metaphor is to say only one concept: whatever "right" can be a thing you would like to be, that "thing" will always go its own way, with a "best compromise" logic, when applied on a wide population. You can "influence it", not change it in its nature.
But programming should be a science, not a religion.
Smart pointers everywhere is wrong as RAII everywhere is wrong.
The good programmer choose the –case by case- the pattern that best fits please note the program needs (not his own needs). Object lifetime is not always something you can decide aprioristically. And "determinism" is not the concept you mention (well … not in the official mathematical sense). Destruction by reference counting is deterministic as destruction in scope. (Smart pointers are destroyed by scope, after all…) GC isn't because the destruction action is not taken as direct consequence of a program action.
To say "I don't have problem because I don't use it" describing another pattern as a replacement for that, doesn't make a good impression. There's nothing scientifically meaningful in that.
I use reference counting widely without any particular problem. As I use RAII. I'm diffident of GC in C++ program, not because I'm diffident on GC, but because I don't see (unlike for RAII and smart pointer) any binding with any C++ native scoping mechanism.
2 bugs found.
> recompile ...
65534 bugs found.
|
|
|
|
|
emilio_grv wrote:
Roland Pibinger wrote:
What are your problems with reference counting smart pointers?
None, because I don't use them. (in general, the same as for auto_ptr plus the unnecessary dynamically allocated counter object in each r.c.s.p.)
Well, I think there's too much religion and very few science in this kind of answers ..
Smart pointers everywhere is wrong as RAII everywhere is wrong.
As I said before, RAII can hardly be overused (at least I don't see how).
The good programmer choose the –case by case- the pattern that best fits please note the program needs (not his own needs). Object lifetime is not always something you can decide aprioristically.
You start case by case and gradually develop towards styles, idioms, patterns. A library, e.g., must conform to a certain 'philosophy' to be usable. The little sister of KISS is KIU (Keep It Uniform ).
And "determinism" is not the concept you mention (well … not in the official mathematical sense). Destruction by reference counting is deterministic as destruction in scope. (Smart pointers are destroyed by scope, after all…)
If you return a smart pointer to a resource that may be returned again then you can hardly call this 'deterministic'. The usage of 'deterministic' here is close to the ACID properties of database transactions (see also link to Herb Sutters article above).
To say "I don't have problem because I don't use it" describing another pattern as a replacement for that, doesn't make a good impression. There's nothing scientifically meaningful in that.
I don't use resource-owning smart pointers because they mix two unrelated concepts: (de-)referencing and resource-handling. Besides that, 'smart pointers' are not pointers, i.e. they cannot provide the full syntax of pointers.
I use reference counting widely without any particular problem.
IMO, reference-counting works well when it's an implementation detail, invisible to the user (when r.c. is encapsulted).
|
|
|
|
|
You're still climbing glasses, my friend!
Many acronym and citation... and no samples by you!
Let me do a counter example: consider an application that lets a user editing a document by placing, moving and removing a variety of objects (in human-language common sense). Think to MS PowerPoint, for example.
The fact that the user has a "delete" command in a menu, doesn’t make you able to "destroy by scope". The scope in which the objects live is the document. If you destroy the document you destroy the objects. Right: RAII factory works.
But what about a "delete" command? You can remove the objects –oops! The object pointers- from the objects collection that represent the document [1], but the objects will be still there until the document will be closed.
Now, think a user inserting 10 thousand object, "deleting" them, inserting other 10 thousand ... three four five ... one hundred times. When do you'll ever eliminate the "deleted" 100thousand objects?
Are you going to fill-up the entire memory with things the users will no more access anyway?
Now, consider a reference counting pointer with casting capability inside a collection, and all object sharing a same common base. The user choose "delete", and you remove the "pointer" from the collection representing the document. Full stop. The object will continue to exist only if it is also referred from inside another collection (for example an "undo" list) and will be deleted when no more needed[2].
You can think this is ugly, you can find as many people you want that agree. Burt you cannot say this doesn't work, or that it "has problems"! That fact that many people agree on something doesn't make that something "true". Fore a science things are "true" when replicate coherently, independently on "opinions". "Good" and "Bad" .. it is another story.
If this "have problems" tell me "what are the problems". I don't see any. May be I'm wrong, but you did nothing to explain me. You simple say "I feel this's wrong".
But saying "I don't use so I don't have problem ..." is like saying by definitiomn "true = good / false = bad". That's not a definition. It's a prejudice.
[1] Please note that such a collection must have a polymorphic content: hence forget about the STL "value semantic": pointers and virtual function, in these cases, are a must. Inheritace of template parameter (that is: policy design of the objects) doesn't help a lot.
[2] This is still "determinism" since "when no more needed" is a well defined and predictable event. The fact that someone use this name in more strict definition, doesn't change the nature of things. "Deterministic" is a legitimate Englis dictionary term. And the fact that someone use acronyms to give a "hidden name" to this misinterpretation of words, doesn't change the physics, nor the language. It is not "when someone will be interested in looking if no more needed", like in GC. That's non-determinism.
Again: you can think this is "hugly", but you cannot say "it's wrong".
2 bugs found.
> recompile ...
65534 bugs found.
|
|
|
|
|
emilio_grv wrote:
You're still climbing glasses, my friend!
Many acronym and citation... and no samples by you!
Let me do a counter example: consider an application that lets a user editing a document by placing, moving and removing a variety of objects ... Are you going to fill-up the entire memory with things the users will no more access anyway?
Maybe my emamples are somewhat misleading (I consider updating them). The article states the "Minimal Scoping Rule" and has a chapter 'Disposing Objects'.
Now, consider a reference counting pointer with casting capability inside a collection, and all object sharing a same common base. The user choose "delete", and you remove the "pointer" from the collection representing the document. Full stop. The object will continue to exist only if it is also referred from inside another collection (for example an "undo" list) and will be deleted when no more needed[2].
Your document example is very interesting. I'd say that the document is a RAII-factory that owns all created objects. Two 'views' work on that document: one consists of the visible objects and the other of the objects that are currently invisible but still part of the document. Objects without further usability are disposed.
The article already is too long. I've considerd to include a longer, more realistic, example, e.g. an XML document where elements are viewed as (a hierarchy of) RAIIFactories that create and own child-elements and attributes.
You can think this is ugly, you can find as many people you want that agree. Burt you cannot say this doesn't work, or that it "has problems"! That fact that many people agree on something doesn't make that something "true". Fore a science things are "true" when replicate coherently, independently on "opinions". "Good" and "Bad" .. it is another story.
Well, this is not an article about the (dis-)advantages of 'smart pointers'. I almost regret to have mentioned them in the article since they seem to distract people from the actual contents.
[1] Please note that such a collection must have a polymorphic content: hence forget about the STL "value semantic": pointers and virtual function, in these cases, are a must. Inheritace of template parameter (that is: policy design of the objects) doesn't help a lot.
You may want to have a look at my other CP article: ptr_vector[^] which could be used/combined/merged with a RAIIFactory.
[2] This is still "determinism" since "when no more needed" is a well defined and predictable event. The fact that someone use this name in more strict definition, doesn't change the nature of things. "Deterministic" is a legitimate Englis dictionary term. And the fact that someone use acronyms to give a "hidden name" to this misinterpretation of words, doesn't change the physics, nor the language. It is not "when someone will be interested in looking if no more needed", like in GC. That's non-determinism. Again: you can think this is "hugly", but you cannot say "it's wrong".
I think it is unfruitful to stick to one word: If you prefer call it: 'resource management bound to one function scope or one block scope'. That's what it is.
Thank you for your elaborate comment!
|
|
|
|
|
Nice anwer, but there's still one point I don't get:
I'd say that the document is a RAII-factory that owns all created objects. Two 'views' work on that document: one consists of the visible objects and the other of the objects that are currently invisible but still part of the document. Objects without further usability are disposed
How do you know they have no "further usability"? I don't see anything keeping track of this. The RAII factory says "You exist until I exist". The concept of "usable" is not there. You must count who's using. But this is –back again- reference counting. That doesn't mean by itself "smart pointers", but you still have to count! (see back "rm82" message ...)
Or you can "migrate" a user "deleted" object to another factory... that will destroy sooner; violating the pattern.
You may want to have a look at my other CP article: ptr_vector which could be used/combined/merged with a RAIIFactory.
Sure: it works fine. But the point is not the "pointer", but what it points: must be a (same) interface that each different object "reinterpret". You call "paint". But "paint" paints differently depending on object type. But this is something that does not relate to refocounting or RAII, but with polymorphism. That's another story.
2 bugs found.
> recompile ...
65534 bugs found.
|
|
|
|
|
emilio_grv wrote:
Nice anwer, but there's still one point I don't get:
I'd say that the document is a RAII-factory that owns all created objects. Two 'views' work on that document: one consists of the visible objects and the other of the objects that are currently invisible but still part of the document. Objects without further usability are disposed
How do you know they have no "further usability"? I don't see anything keeping track of this. The RAII factory says "You exist until I exist". The concept of "usable" is not there.
You are right, it's not there, because it is application logic. The RAIIFactory only encapsulates resource handling via RAII so that "allocation and deallocation disappear from the surface level of your code."
You must count who's using. But this is –back again- reference counting. That doesn't mean by itself "smart pointers", but you still have to count! (see back "rm82" message ...)
You probably mean a situation, where many 'subscribers' reference the same 'published' resource. In this case you probably find an easier solution with (internal or external) refernce-counting (but that makes it harder to track down the lifetime of a resource). RAII, scope bound resource management to be more precise, is not a panacea but it works very well in many cases. Not all though. 
|
|
|
|
|
I have trouble with your smart pointer definitions too.
To me at least, they are totally deterministic. When the last smart pointer assigned to a pointer is deleted, the pointed-to object will be deleted. Just because it may not happen in a function or trivial scope doesn't mean it's non-deterministic.
I also think your advice to avoid returning resources from functions (and presumably acting as sinks too) is misguided. It's a common, well-known and useful C++ idiom. (See Sutter's books or even his treatise online)
The rest of your article was reasonable and you should be applauded for discouraging the use of new/delete. Although I have to say I would avoid using your RAII factories in favour of smart pointers and standard containers. IMO they are more robust, readable and, well, standard.
|
|
|
|
|
MattyT wrote:
I have trouble with your smart pointer definitions too.
To me at least, they are totally deterministic. When the last smart pointer assigned to a pointer is deleted, the pointed-to object will be deleted. Just because it may not happen in a function or trivial scope doesn't mean it's non-deterministic.
You may call it 'resource management bound to one function scope or one block scope' instead of 'deterministic resource management'. Ref-counted smart pointers are not bound to one scope.
I also think your advice to avoid returning resources from functions (and presumably acting as sinks too) is misguided. It's a common, well-known and useful C++ idiom. (See Sutter's books or even his treatise online)
Hmm,
- "Make a habit of using smart pointers like auto_ptr in your daily work" (Herb Sutter, October 1999)
- "Avoid using auto_ptr" (Herb Sutter, August 2004)
Ok, to be fair, the full quotation of the last sentence is: "Avoid using auto_ptr, instead use shared_ptr which is widely available and being added to the standard library." And to avoid misunderstanding: I recommend of course his books (I have the two 'Exceptional C++') and all his articles, Gotw, ...
It seems to me that many 'smart pointers' (like auto_ptr) are so smart that they outsmart their users. 
|
|
|
|
|
Hi,
good article.
But is RAII really so good,
that GC is not necessary anymore?
Furthermore, is it true, that
"Exception handling gets complicated in GC languages ".
In Java and .Net Exception handling is the standard way
of error handling and both have GC.
I beleive that you are a bit overoptimistic about RAII.
Best Regards
Martin
|
|
|
|
|
GC is not a replacement for RAII. It can handle only memory, while leaving all other resources (db connections, files, GDI handles, sockets...) to programmer to handle manually. One solution is to have them both, like in C++/CLI, but I strongly prefer to have GC only as an option on a per-object basis. As for .NET and Java, I have seen so many programmers (heck, even book writers) write exception non-safe code, that I would argue these environments are seriously flawed in this regard. See this article by Reymond Chen[^], for instance.
Anyway, I voted this article 5, although I don't quite agree with author's criticisms for smart pointers. I use Boost smart pointers (especially scoped_ptr) all the time, and practically never call delete manually any more. As for RAII factory, I used this idiom once (although I had no idea it was called RAII factory ) when I didn't have a clear owner of my objects and wanted to avoid the overhead of reference counting. However, I exactly new the point in my program where it was safe to destruct the objects - it is not always the case.
Finally, I recommend this article[^] as a nice introduction to RAII.
<a href = http://www.codeproject.com/script/profile/whos_who.asp?id=14112#Blog> My programming blahblahblah blog. If you ever find anything useful here, please let me know to remove it.
|
|
|
|
|
Nemanja Trifunovic wrote:
GC is not a replacement for RAII. It can handle only memory, while leaving all other resources (db connections, files, GDI handles, sockets...) to programmer to handle manually.[...] As for .NET and Java, I have seen so many programmers (heck, even book writers) write exception non-safe code, that I would argue these environments are seriously flawed in this regard. See this article by Reymond Chen[^], for instance.
That's the point. Many programmers in GC languages seem to be unaware of the problematic of releasing resources and the right resource-handling idioms (e.g. the 'Null' object).
Anyway, I voted this article 5, although I don't quite agree with author's criticisms for smart pointers. I use Boost smart pointers (especially scoped_ptr) all the time, and practically never call delete manually any more.
Yes, real C++ programmers don't call delete manually. Seriously!
I also use scoped resource handlers for just one object (but not 'smart pointers') in some cases when it's not possible to create the object on the stack.
Finally, I recommend this article[^] as a nice introduction to RAII.
Good article. I've known it. Unfortunately it does not define RAII, it assumes that you already know RAII.
|
|
|
|
|
Roland Pibinger wrote:
Yes, real C++ programmers don't call delete manually. Seriously!
Yep, real programmers don't need to dynamically allocate everything on the planet like 99% of supposed "programmers" out there. Please ignore this - just a game programmer's view of the trends of programming in general... bloat all the way! 
|
|
|
|
|
Rompa wrote:
Yep, real programmers don't need to dynamically allocate everything on the planet like 99% of supposed "programmers" out there.
Well, students nowadays learn Java as 'base language' in their CS courses ... 
|
|
|
|
|
Martin Holzherr wrote:
Hi,good article.
Thank you!
But is RAII really so good,that GC is not necessary anymore?
IMO, yes for C++, maybe no for other languages.
Furthermore, is it true, that
"Exception handling gets complicated in GC languages ".
In Java and .Net Exception handling is the standard way
of error handling and both have GC.
In Java (the language I have worked with) the user has to write code over and over again that in C++ can be written in the destructor once and forever.
I believe that you are a bit overoptimistic about RAII.
Maybe. The RAII idiom is underestimated in C++. Partly because of the bad name, partly because RAII is not so "smart" as some "policy-based" designs.
RAII is not a panacea but a cure for most resource management problems. And it can hardly be overused. 
|
|
|
|
|
|
|
General News Suggestion Question Bug Answer Joke Praise Rant Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
|
|