dumb things about smart ptrs [rant]

Started by
27 comments, last by cypherx 18 years, 10 months ago
Quote:Original post by Verg
These should be standard for ALL smart pointer types:


Your opinion, which I disagree with ^_^. Prehaps something like:

boost::shared_ptr< int > foo;
foo = boost::share( new int );

Or something of similar shorterness that autopromotes a raw pointer to an auto pointer (so that when you have a shared_ptr to huge_name_with< multiple< template_parameters < etc < etc < etc< pie > > > > > you don't have so much to type). But personally I prefer the safety that comes with disallowing direct assignment (foo = new int). It makes this all too easy:
int * foo = new int;boost::shared_ptr< int > bar;//...bar = foo;//...delete foo;//when bar goes out of scope, it too will attempt to delete bar!!!

Quote:My opinion is: with the exception of the lack of "garbage collection", a smart pointer should act like a pointer. I don't want the smart pointer to have its own methods which are called through the dot (.) resolution operator. How retarded to have both this:

ptr->hi()

and this!

ptr.ref_count()

!!


How retarded is it to care? Seriously, if you don't want to use the functions available through the dot operator, just don't use them. Of course this means you won't be using std::auto_ptr<>'s .release() member, or any similar extra optional functionality provided by smart pointers...

Quote:And if I can't make a simple assignment from bald pointer to smart pointer, I have to either set the smart pointer in the containing class's initializer list (not always practical), or use the retarded "reset()" method through the dot operator. >:-(

I realize the designers of the boost::smart_ptr libraries are trying to make the world safe for pointers; but by disallowing both of the above, they're giving us basically a glorified wrapper with an overridden -> operator. What's the use? May as well use reference variables, if you can't do simple pointer assignment.


The use is simply eliminating the need to do reference variables. It's little extra typing, but tracking it for every object can be impractical - especially if you don't have access to the class definition itself (std::string, etc). The fact that boost::invasive_ptr supports allowing you to do your own reference counting emphisizes this point.

Quote:IMO you shouldn't have to accomodate the smart pointer class (by using SmartPointerType<T>::reset() or something to assign a pointer)... the smart pointer class should (relatively) easily take the place of a bald pointer.


Easy? Sure, as long as it's not "Easy to shoot off your foot with". Direct assignment is this as far as I'm concerned - with shared_ptr anyways.

Quote:The reason I'm b!tching

For gods sake, either say bitching or don't.
Quote:at all is that there is a bug in Loki's "FixedAllocator" class which causes an assert failure when storing a Loki::Functor pointer inside a Loki::SmartPtr. The CVS has apparently fixed that bug; but I (on my wee little lonesome) came across a new bug in the CVS which causes a different assert... so now the application code has ground to a halt.

We tried temporarily defining "__LOKI_REPAIR__" and RE-defining all "functor ptr types" in the app, based on that define... to use boost::shared_ptr... and naturally, those conversions (shown above) weren't going to happen...


Do loki pointers do intrusive reference counting? If so, you may have a friend in boost::intrusive pointer. If you look at the documentation on it, you'll notice this little ball of joy:

intrusive_ptr(T * p, bool add_ref = true);

Is _NOT_ marked explicit. This is perfectly legal:

some_object * foo = new some_object;
boost::intrusive_ptr< some_object > bar;
bar = foo;

Quote:It's just plain-as-the-nose-on-my-face DUMB to have a "smart pointer" act like anything other than a "pointer"


By that argument, it's dumb to have a pointer that automatically deletes what's pointed to once it goes out of scope. That is, it makes anything that looks like a pointer but isn't "DUMB". Thus, I disagree - the differences are what make smart pointers BETTER than raw pointers. If the goals focused on in a given implementation are not the same as your own, that's your problem.

The problem for you is that boost::shared_ptr is meant to be fairly lightweight. There's no hidden manager with a hash map of pointers - this will cause multiple deletion:

boost::shared_ptr< int > a ( new int );
boost::shared_ptr< int > b ( a.get() ); //Constructs B from a raw pointer.

The only time assigning a shared_ptr to a raw pointer makes sense IMHO is if you yourself are allocating it, in which since it makes more sense to never have a raw pointer in the first place. E.g. you don't do:

int * foo = new int;
...
boost::shared_ptr< int > bar( foo );
...
//here is where a programmer who skimming the code missed the decleration of bar, will think foo is being leaked, and thus add:
delete foo;
//here is where the program will delete foo a second time.

You do:

boost::shared_ptr< int > foo( new int );
...
boost::shared_ptr< int > bar( foo );
...
//here is where nobody will add delete foo, because they realize off the bat foo is a smart pointer.


Just adding some defence for shared_ptr. HTH, and again, try looking into intrusive_ptr. It's there for more reasons than just optimization, you know...
Advertisement
Quote:Original post by MaulingMonkey
Quote:Original post by Verg
These should be standard for ALL smart pointer types:


Your opinion, which I disagree with ^_^. Prehaps something like:

boost::shared_ptr< int > foo;
foo = boost::share( new int );

Or something of similar shorterness that autopromotes a raw pointer to an auto pointer (so that when you have a shared_ptr to huge_name_with< multiple< template_parameters < etc < etc < etc< pie > > > > > you don't have so much to type). But personally I prefer the safety that comes with disallowing direct assignment (foo = new int). It makes this all too easy:
int * foo = new int;boost::shared_ptr< int > bar;//...bar = foo;//...delete foo;//when bar goes out of scope, it too will attempt to delete bar!!!




But doncha see? I understand all that. You could also do this:

foo = new T();{  SmartPtrType1<T> bar1 = foo;  SmartPtrType2<T> bar2 = foo;}// uh oh! Both go out of scope, and try to delete "foo"


All I'm saying is that... as long as you understand the dangers of pointers, why can't you use them for what they're good for?

Quote:
Quote:My opinion is: with the exception of the lack of "garbage collection", a smart pointer should act like a pointer. I don't want the smart pointer to have its own methods which are called through the dot (.) resolution operator. How retarded to have both this:

ptr->hi()

and this!

ptr.ref_count()

!!


How retarded is it to care? Seriously, if you don't want to use the functions available through the dot operator, just don't use them. Of course this means you won't be using std::auto_ptr<>'s .release() member, or any similar extra optional functionality provided by smart pointers...


General "release" functions defined in the boost namespace could take care of that... but shared_ptr doesn't even allow "release".

So, what happens when you need to delete something early? Tough luck!

Quote:
Quote:IMO you shouldn't have to accomodate the smart pointer class (by using SmartPointerType<T>::reset() or something to assign a pointer)... the smart pointer class should (relatively) easily take the place of a bald pointer.


Easy? Sure, as long as it's not "Easy to shoot off your foot with". Direct assignment is this as far as I'm concerned - with shared_ptr anyways.


There it is. Let me shoot my foot off. I'm not a 12-year-old who's handling a gun for the first time, if we extend the metaphor [smile]

Quote:
Quote:The reason I'm b!tching

For gods sake, either say bitching or don't.


Hey... some people may be sensitive [grin]

Quote:
Quote:It's just plain-as-the-nose-on-my-face DUMB to have a "smart pointer" act like anything other than a "pointer"


By that argument, it's dumb to have a pointer that automatically deletes what's pointed to once it goes out of scope. That is, it makes anything that looks like a pointer but isn't "DUMB".


Well... I thought I'd said "except for garbage collection" [smile] ... but that aside...

Quote:
The problem for you is that boost::shared_ptr is meant to be fairly lightweight. There's no hidden manager with a hash map of pointers - this will cause multiple deletion:

boost::shared_ptr< int > a ( new int );
boost::shared_ptr< int > b ( a.get() ); //Constructs B from a raw pointer.


Sure, there's always a way to shoot your foot off. But if the designers of smart pointer classes weren't so worried about people doing that... and designed a smart pointer class for people who actually know what they're doing... then the pointer wouldn't be something that required special attention; there would be no special methods to call for assignments; there would be no extra code (aside from an occasional call from pointernamespace::release() or something)...

Quote:
The only time assigning a shared_ptr to a raw pointer makes sense IMHO is if you yourself are allocating it, in which since it makes more sense to never have a raw pointer in the first place. E.g. you don't do:

int * foo = new int;
...
boost::shared_ptr< int > bar( foo );
...
//here is where a programmer who skimming the code missed the decleration of bar, will think foo is being leaked, and thus add:
delete foo;
//here is where the program will delete foo a second time.

You do:

boost::shared_ptr< int > foo( new int );
...
boost::shared_ptr< int > bar( foo );
...
//here is where nobody will add delete foo, because they realize off the bat foo is a smart pointer.


That's something we never do; but if it were "allowed", then something like this could happen:

boost::shared_ptr<T> ptr = new T();   // what's to delete? 


Quote:
Just adding some defence for shared_ptr. HTH, and again, try looking into intrusive_ptr. It's there for more reasons than just optimization, you know...


I appreciate your thoughts, and the discussion.


Chad
my_life:          nop          jmp my_life
[ Keep track of your TDD cycle using "The Death Star" ] [ Verge Video Editor Support Forums ] [ Principles of Verg-o-nomics ] [ "t00t-orials" ]
BTW... the only reason we want to do this:

boost::shared_ptr<T> ptr = new T();


instead of this:

boost::shared_ptr<T> ptr(new T());


is that the pointer object is a class member which can't be initialized when the owning class is created.

class owner{//blah blah blahprivate:boost::shared_ptr<OtherClass>  m_pointer;   // can't be initialized when                                            // owner is constructed};
my_life:          nop          jmp my_life
[ Keep track of your TDD cycle using "The Death Star" ] [ Verge Video Editor Support Forums ] [ Principles of Verg-o-nomics ] [ "t00t-orials" ]
If you hate all of the safety features, I don't see why you want smart pointers. If you "know how pointers work" and don't want the safety, why not use raw pointers?

The reason is: programmers, no matter how good, will make mistakes. The harder it is to make mistakes, the fewer that will be made. If you can find a way to trade dangerous functionality for safety, then you win.
Quote:Original post by Daniel Miller
If you hate all of the safety features, I don't see why you want smart pointers. If you "know how pointers work" and don't want the safety, why not use raw pointers?


Garbage collection! Woo hoo!

[grin]


my_life:          nop          jmp my_life
[ Keep track of your TDD cycle using "The Death Star" ] [ Verge Video Editor Support Forums ] [ Principles of Verg-o-nomics ] [ "t00t-orials" ]
Is there any reason you're using C++ in the first place? There are plenty of alternative higher-level languages out there--python, ruby, O'Caml, or even lisp or java if you're into that sort of thing.
Quote:Original post by Verg
General "release" functions defined in the boost namespace could take care of that... but shared_ptr doesn't even allow "release".


Yes it does. It's called reset().


Quote:
Sure, there's always a way to shoot your foot off. But if the designers of smart pointer classes weren't so worried about people doing that... and designed a smart pointer class for people who actually know what they're doing...


I don't see what your problem is. The boost smart pointer library has its own set of design goals. If yours are different, then why don't you write your own smart pointer class? It's not difficult.
Quote:Original post by bytecoder
Is there any reason you're using C++ in the first place? There are plenty of alternative higher-level languages out there--python, ruby, O'Caml, or even lisp or java if you're into that sort of thing.


No; it's just an easy language to develop in.

I guess, in a way, we've run into a sort of "show stopping" problem; either we modify the code (i.e. "add" a bunch of lines) directly, or wait for Loki's SmallObj class to be repaired.

The added code would be along the lines of creating temporaries, and then assigning the temporaries to the class members (extra code; unnecessary if Loki's smart ptr worked as advertised!)

Thanks for the suggestion.
my_life:          nop          jmp my_life
[ Keep track of your TDD cycle using "The Death Star" ] [ Verge Video Editor Support Forums ] [ Principles of Verg-o-nomics ] [ "t00t-orials" ]
Quote:Original post by Oxyacetylene
Quote:Original post by Verg
General "release" functions defined in the boost namespace could take care of that... but shared_ptr doesn't even allow "release".


Yes it does. It's called reset().


Doesn't "reset()" do an assignment? I guess you could use "reset(0)" for a type of release; but many "release()" implementations return the reference count.

...

As far as writing a new smart pointer class... it would probably use policies... which is why we're waiting for Loki to be fixed... [smile]

A stop-gap solution might not be a bad idea though. Thanks for the thoughts.
my_life:          nop          jmp my_life
[ Keep track of your TDD cycle using "The Death Star" ] [ Verge Video Editor Support Forums ] [ Principles of Verg-o-nomics ] [ "t00t-orials" ]
Quote:Original post by Andrew Russell
Sorry Verg, I'm afraid that you're missing the point on this one [smile].

Smart pointers use this method for very good reasons.


You're probably right; the rant is semi-serious, anyway. The sneaking suspicions are crawling up my back right now... and probably were from the start...

Garbage collecting, ref-counted, (semi)-smart pointers... where are you?
my_life:          nop          jmp my_life
[ Keep track of your TDD cycle using "The Death Star" ] [ Verge Video Editor Support Forums ] [ Principles of Verg-o-nomics ] [ "t00t-orials" ]

This topic is closed to new replies.

Advertisement