468,463 Members | 2,034 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,463 developers. It's quick & easy.

Poll: Do you use smart pointers?

Someone made the statement in a newsgroup that most C++ programmers use
smart pointers. His actual phrase was "most of us" but I really don't think
that most C++ programmers use smart pointers, but I just don't know.

I don't like them because I don't trust them. I use new and delete on pure
pointers instead.

Do you use smart pointers?
Sep 22 '06
92 4445
Noah Roberts schrieb:
Thomas J. Gritzan wrote:
>What costs does shared_ptr have that weak_ptr doesn't have?

weak_ptr doesn't do any counting. It provides access to the pointer
and to the reference when needed but doesn't do any upkeep so is pretty
close to a raw pointer.
Wrong.

A shared_ptr object holds to pointers: One to the counted object, one to
the management structure. The last shared_ptr object drops the reference
count to zero and deletes the counted object.

But the management structure is also a shared object and can't be deleted
until the last weak_ptr is gone. So weak_ptr does count.

I just checked in my boost implementation: weak_ptr holds a weak_count
object, which does this in its destructor:

~weak_count() // nothrow
{
if(pi_ != 0) pi_->weak_release();
// [...]
}

And some add_ref calls in the constructors and assignment operators.

--
Thomas
http://www.netmeister.org/news/learn2quote.html
Sep 22 '06 #51

Alf P. Steinbach wrote:
* Noah Roberts:
Thomas J. Gritzan wrote:
What costs does shared_ptr have that weak_ptr doesn't have?
weak_ptr doesn't do any counting. It provides access to the pointer
and to the reference when needed but doesn't do any upkeep so is pretty
close to a raw pointer.

Are you sure about that? I haven't checked any implementation, but a
weak pointer must be able to detect whether the managed object still
exists or not, in order to not conjure up a non-null shared_ptr for an
already destroyed object.
Nope, I hadn't thought of that. This is why I don't spend a lot of
time trying to make my own when not forced to by management. We
haven't even reached the point where you are - we still use raw
pointers except where I've used a broken smart pointer I made for a
particular purpose. Everyone else is miles from being convinced to use
them. So we play with leaks and dangling pointers instead.

Sep 22 '06 #52
rp*****@yahoo.com (Roland Pibinger) writes:
Real pointers don't transfer ownership because the never own any
pointed-to object.
Whether or not ownership is transferred is a conceptional issue. If
the code calling the pointer-producing function is supposed to free
the pointer than ownership is transferred.
No try/catch cascades, just pure RAII as described by Stroustrup:
http://www.artima.com/intv/modern3.html.
So how does that differ from shared_ptr? shared_ptr doesn't transfer
ownership, shared_ptr keeps ownership. That's exactly what Stroustrup
was promoting.

The only minor exception is during initialisation:

shared_ptr< some_t ptr(new some_t(...));

But that's highly idiomatic.

Is this initialisation what the fuss is about?

If so, write a small wrapper

template< typename T // this following for any number of params
shared_ptr< T init_shared_ptr(T1 const& t1, T2 const& t2)
{
return shared_ptr< T >(new T(t1, t2));
}

and take shared_ptr and init_shared_ptr _together_ as a library that
confines ownership.

Jens
Sep 22 '06 #53
On Fri, 22 Sep 2006 20:22:30 GMT in comp.lang.c++, rp*****@yahoo.com
(Roland Pibinger) wrote,
>Which "Correctness"? The 'usual' smart pointers use questionable
"transfer of ownership" semantics and don't check for NULL before they
dereference a pointer. The following compiles without a warning on
popular compilers:

int i = 0;
auto_ptr<intap (&i);
The above is a user problem, not a auto_ptr problem. The same as if
you just wrote 'delete &i;'

In my opinion, auto_ptr should no longer be regarded as "the usual"
smart pointer, at least for new code. Boost::shared_ptr is my usual
smart pointer, with safer and more flexible behavior at the cost of
some comparatively very cheap memory and CPU cycles. tr1:: if you
have it.

auto_ptr is still OK in cases where it applies. I fixed some code
based on a Microsoft sample by adding some auto_ptr<>s. The API
returns pointers to 'new'ed objects (for no good reason) that the
user is responsible to delete. The original example code leaked
left and right on all the error return paths.
>BTW, even gurus may change their mind
(http://www.gotw.ca/publications/index.htm):
"Most people have heard of the standard auto_ptr smart pointer
facility, but not everyone uses it daily. That's a shame, because it
turns out that auto_ptr neatly solves common C++ design and coding
problems, and using it well can lead to more robust code." Herb
Sutter, 1999

"Avoid using auto_ptr, instead use shared_ptr which is widely
available and being added to the standard library." Herb Sutter,
2004.
Apparently he changed in the direction of _more_ smart pointers.

Sep 22 '06 #54

"Thomas Tutone" <Th***********@yahoo.comwrote in message
news:11*********************@b28g2000cwb.googlegro ups.com...
>Also, don't the STL containers require smart pointers which are not
themselves found in the STL?

The standard containers do not require smart pointers, but using smart
pointers with the standard containers makes life much easier than using
the standard containers with raw pointers.
>It seems to me that things like std::vector
require using something like the Boost smart pointers.

Not true. Raw pointers work fine, but are a sure recipe for leaks.
He's referring to the fact that std::auto_ptr isn't intended
for standard containers due to its copy semantics. Before
tr1, you had to use boost or some other implementation if you
wanted containers of smart pointers. This is no longer the
case with tr1.


Sep 22 '06 #55
Stuart Golodetz wrote:
"Jim Langston" <ta*******@rocketmail.comwrote in message
news:xU*************@newsfe04.lga...
>Someone made the statement in a newsgroup that most C++ programmers use
smart pointers. His actual phrase was "most of us" but I really don't
think that most C++ programmers use smart pointers, but I just don't know.

I don't like them because I don't trust them. I use new and delete on
pure pointers instead.

Do you use smart pointers?
[list redacted]
Good list Stu, but you left off what IMHO is one of the best reasons for
using smart pointers (even just auto_ptr, where appropriate): They make
it easier to write exception safe code.

Sep 23 '06 #56
On Fri, 22 Sep 2006 23:17:04 GMT, David Harmon <so****@netcom.com>
wrote:
>>int i = 0;
auto_ptr<intap (&i);

The above is a user problem, not a auto_ptr problem. The same as if
you just wrote 'delete &i;'
It's an auto_ptr problem because it violates a basic principle of the
Standard libraries (C and C++): don't delete (free) what you haven't
allocated. The same appplies to auto_ptr's 'destructive copy
semantics'.
>In my opinion, auto_ptr should no longer be regarded as "the usual"
smart pointer, at least for new code. Boost::shared_ptr is my usual
smart pointer, with safer and more flexible behavior at the cost of
some comparatively very cheap memory and CPU cycles. tr1:: if you
have it.
What is 'safer' with shared_ptr. Does it check for NULL pointers
before dereferncing? Does it protect you against:
int i = 0;
shared_ptr<intap (&i);
Do 'custom deleters' relly enhance safety?
Is it appropriate for a 'pointer' class (template) which is intended
to replace real pointes to internally allocate a counter for each
pointed-to object? (Real pointes are ultra-lightweight objects, like
an int).

Best wishes,
Roland Pibinger

Sep 23 '06 #57
"red floyd" <no*****@here.dudewrote in message
news:T%****************@newssvr11.news.prodigy.com ...
Stuart Golodetz wrote:
>"Jim Langston" <ta*******@rocketmail.comwrote in message
news:xU*************@newsfe04.lga...
>>Someone made the statement in a newsgroup that most C++ programmers use
smart pointers. His actual phrase was "most of us" but I really don't
think that most C++ programmers use smart pointers, but I just don't
know.

I don't like them because I don't trust them. I use new and delete on
pure pointers instead.

Do you use smart pointers?

[list redacted]

Good list Stu, but you left off what IMHO is one of the best reasons for
using smart pointers (even just auto_ptr, where appropriate): They make
it easier to write exception safe code.
:) To quote from my previous post, "* Making things exception-safe is harder
with raw pointers." I think I should have made it more visible, I squeezed
it in at the bottom of the list.

Regards,
Stu
Sep 23 '06 #58
On 22 Sep 2006 23:19:48 +0100, Jens Theisen <jt***@arcor.dewrote:
>shared_ptr doesn't transfer
ownership, shared_ptr keeps ownership. That's exactly what Stroustrup
was promoting.

The only minor exception is during initialisation:
That's anything but 'minor'!
>shared_ptr< some_t ptr(new some_t(...));

But that's highly idiomatic.
Rather idiosyncratic than idiomatic (there is another word starting
with 'idio' that could be used here :-)
>Is this initialisation what the fuss is about?

If so, write a small wrapper

template< typename T // this following for any number of params
shared_ptr< T init_shared_ptr(T1 const& t1, T2 const& t2)
{
return shared_ptr< T >(new T(t1, t2));
}

and take shared_ptr and init_shared_ptr _together_ as a library that
confines ownership.
In general, you need ref-counting only when you _return_ 'ownership'
form a function (which is bad style anyway). In other cases
ref-counting is unnecessary. What would be the use of counting? When
you don't return ownership you know in advance when/where the
ref-counter drops to 0. It's the same scope in which you have created
the ref-counted object (disregarding contrived examples with static or
global ref-counted objects). Most examples of shared_ptr I have seen
so far don't need any ref-counting because they either don't return
ownership or the return of ownership can easily be avoided.

Best wishes,
Roland Pibinger


Sep 23 '06 #59
On Fri, 22 Sep 2006 14:10:11 -0600, Jerry Coffin <jc*****@taeus.com>
wrote:
>No try/catch cascades, just pure RAII as described by Stroustrup:
http://www.artima.com/intv/modern3.html. The pattern was called
"Object As Sole Owner" by Cargill in his seminal article which is now
available online: http://www.ddj.com/184409895

The idea wasn't particuarly new then. Just for example, look toward the
end of:
http://tinyurl.com/nz6pf
It's not new but obviously not well known. IMO, the essence of 'real'
RAII (and the main reason for still using C++) is that it guarantees
both, automatic and deterministic (ie. scope bound) resource
management.

Best wishes,
Roland Pibinger
Sep 23 '06 #60
rp*****@yahoo.com (Roland Pibinger) writes:
In general, you need ref-counting only when you _return_ 'ownership'
form a function (which is bad style anyway).
You don't return ownership. shared_ptr owns it's object and you return
a shared_ptr. If you return a shared_ptr from a function, that doesn't
mean that ownership is transferred - after all the function returning
it can still keep a copy.
In other cases
ref-counting is unnecessary. What would be the use of counting?
The question is: Why would you not? What's actually the problem?

As far as I can see, you are trying to make the following points:

1) new/delete asymmetry

2) some point about ownership that I don't fully understand

3) reference counting overhead which is sometimes unnecessary

4) spurious allocation that is sometimes unnecessary

5) additional indirection overhead

For 1, use the wrapper if you take it as that important.

For 2, can you elaborate what you mean?

For 3 - 5, the overhead is fairly small and generally considered worth
the safety. The spurious allocation is also worth the safety, but
could be alleviated by intrusive counting that you will probably also
disapprove of.

Did I miss a point?

One last question: How do you return expensive objects, a
vector, say, from a function?

Regards,

Jens
Sep 23 '06 #61
rp*****@yahoo.com (Roland Pibinger) writes:
It's an auto_ptr problem because it violates a basic principle of the
Standard libraries (C and C++):
That a stupid principle anyway. In C, it means that functions have to
return an internal buffer, non-reentrency being the consequence. In
C++, I'd like to draw attention to the problem that deleting
incomplete types don't call destructors. So my advice would rather be:
don't ever use free or delete, and don't make libraries that force
users to do so.

In C++, we have smart pointers to avoid doing so and in C there are
other ways. The APR framework let's you allocate object with respect
to a pool, and all objects are freed when the pool is freed - these
pools again being organised in an hierarchical manner that ususally
corresponds to the stack frame. That leads to a style of C programming
where you again have various allocations, but no explicit
deallocations.
What is 'safer' with shared_ptr. Does it check for NULL pointers
before dereferncing?
Indeed, it might be worth having a variant of shared_ptr that's not
allowed to be null. Good idea. :)
Does it protect you against:
int i = 0;
shared_ptr<intap (&i);
That's hardly a mistake you do accidently.
Do 'custom deleters' relly enhance safety?
I don't know. But they are not a central feature anyway.
Is it appropriate for a 'pointer' class (template) which is intended
to replace real pointes to internally allocate a counter for each
pointed-to object? (Real pointes are ultra-lightweight objects, like
an int).
So it's the _name_ you don't like?

Regards,

Jens
Sep 23 '06 #62
Roland Pibinger wrote:
On Fri, 22 Sep 2006 23:17:04 GMT, David Harmon <so****@netcom.com>
wrote:
>int i = 0;
auto_ptr<intap (&i);
The above is a user problem, not a auto_ptr problem. The same as if
you just wrote 'delete &i;'

It's an auto_ptr problem because it violates a basic principle of the
Standard libraries (C and C++): don't delete (free) what you haven't
allocated. The same appplies to auto_ptr's 'destructive copy
semantics'.
Where in the standard to you find that principle? Most everyone was
originally a little surprised by the destructive copy semantics (but
even that might be addressed in C++0x; see
http://groups.google.com/group/comp....f227fac949c22).
In my opinion, auto_ptr should no longer be regarded as "the usual"
smart pointer, at least for new code. Boost::shared_ptr is my usual
smart pointer, with safer and more flexible behavior at the cost of
some comparatively very cheap memory and CPU cycles. tr1:: if you
have it.

What is 'safer' with shared_ptr. Does it check for NULL pointers
before dereferncing?
The intent of shared_ptr was to be as close as possible to raw
pointers, and that meant no checking overhead (among other things,
e.g., "deep constness" for the pointee such as std::vector supports).
Such a check could have been made optional with a policy-based design
such as that in Loki's smart pointer, but the Boost authors thought
(rightly, IMHO) that doing that would confuse people and hinder
shared_ptr's adoption. If you want checking, there certainly are smart
pointers that support it.
Does it protect you against:
int i = 0;
shared_ptr<intap (&i);
No, it didn't intend to, and how could it? You can do the same with raw
pointers:

int i = 0;
int *pi = &i;
delete pi;
Do 'custom deleters' relly enhance safety?
Certainly, because they make shared_ptr easily extensible for other
resources than just raw memory. Thus you get exception safety without
having to hand-roll your own class each time.
Is it appropriate for a 'pointer' class (template) which is intended
to replace real pointes to internally allocate a counter for each
pointed-to object? (Real pointes are ultra-lightweight objects, like
an int).
The answer to this may vary from case to case, but as others have
stated in this thread and elsewhere, usually it is well worth the
(minimal) cost. Sounds to us like you're optimizing prematurely.

Cheers! --M

Sep 23 '06 #63
Roland Pibinger wrote:
In general, you need ref-counting only when you _return_ 'ownership'
form a function (which is bad style anyway).
First, you need ref-counting when you share an object among other
objects whose destruction order is indeterminant. It allows you to
easily make sure you don't accidentally delete the object when it is
still needed.

Second, the "bad style" that you're talking about is presumably factory
functions, virtual constructors, and the like. That's a standard design
pattern and well-recieved idiom, not bad style. I know of no one but
you who objects to them. Through this discussion, you cite Stroustrup
as if he's on your side in this. Certainly, he warns against overusing
smart pointers (so do Sutter and Alexandrescu, BTW), but he still
advocates using them, which you do not. Moreover, he advocates the "bad
style" of virtual constructors and factory functions in TC++PL3 15.6.2
and here:

http://www.research.att.com/~bs/bs_f...l#virtual-ctor

In short, I don't think you have any real support for your own
home-grown principles of programming. RAII via smart pointers is
well-established, widely used, and recommended and practiced by all
recognized authorities on the language.

Cheers! --M

Sep 23 '06 #64
On 23 Sep 2006 11:18:21 +0100, Jens Theisen <jt***@arcor.dewrote:
>One last question: How do you return expensive objects, a
vector, say, from a function?
void populate (std::vector<int>& vec) {
using namespace std;
vector<intloc;
loc.reserve (1000);
for (int i = 0; i < 1000; ++i) {
loc.push_back (i);
}
vec.swap (loc);
}

I guess that's not smart enough for you. You may prefer something
like:

boost::shared_ptr <std::vector<int populate () {
....
}

IMO, that's programing Java in C++.

Best wishes,
Roland Pibinger
Sep 23 '06 #65
On 23 Sep 2006 03:58:31 -0700, "mlimber" <ml*****@gmail.comwrote:
>Roland Pibinger wrote:
>In general, you need ref-counting only when you _return_ 'ownership'
form a function (which is bad style anyway).

First, you need ref-counting when you share an object among other
objects whose destruction order is indeterminant. It allows you to
easily make sure you don't accidentally delete the object when it is
still needed.
I don't argue against RAII, quite the contrary. Just ref-counting
makes no sense when you don't return the object (any ref-counted
object, not just a shared_ptr).

void foo () {
shared_ptr<intsp (new int(0));
// assign sp to 100 other shared_ptrs
// pass sp to 100 fuunctions
} // here the ref_count of sp is 0

>Second, the "bad style" that you're talking about is presumably factory
functions, virtual constructors, and the like. That's a standard design
pattern and well-recieved idiom, not bad style.
Neither the C++ Standard library nor the C Standard library use your
'standard design pattern'. Guess why?
>In short, I don't think you have any real support for your own
home-grown principles of programming. RAII via smart pointers is
well-established, widely used, and recommended and practiced by all
recognized authorities on the language.
If I invented that principles I would be a genius ;-)
Of course, there are various sources that suggest that style of
programming - first and foremost the articulate stack-orientation in
the C++ language itself.

Best wishes,
Roland Pibinger
Sep 23 '06 #66
rp*****@yahoo.com (Roland Pibinger) writes:
void populate (std::vector<int>& vec) {
using namespace std;
vector<intloc;
loc.reserve (1000);
for (int i = 0; i < 1000; ++i) {
loc.push_back (i);
}
vec.swap (loc);
}

I guess that's not smart enough for you. You may prefer something
like:

boost::shared_ptr <std::vector<int populate () {
...
}
I indeed would prefer the latter, though I agree, in this example,
it's largely a matter of taste.

However:

How to return an ostream or any other object whiches most derived type
should not be part of the function's signature?

And how do you return expensive-to-copy objects that are not default
constructible?
IMO, that's programing Java in C++.
I could call your way "programming C in C++" as well, though I
appreciate their are different ways with different pros and cons.

Regards,

Jens
Sep 23 '06 #67
On Fri, 22 Sep 2006 06:52:19 -0700, "Jim Langston"
<ta*******@rocketmail.comwrote:
>Someone made the statement in a newsgroup that most C++ programmers use
smart pointers. His actual phrase was "most of us" but I really don't think
that most C++ programmers use smart pointers, but I just don't know.

I don't like them because I don't trust them. I use new and delete on pure
pointers instead.

Do you use smart pointers?
Most of the time, they are more trustworthy then me.

Zara
Sep 23 '06 #68
On Sat, 23 Sep 2006 09:00:46 GMT in comp.lang.c++, rp*****@yahoo.com
(Roland Pibinger) wrote,
>What is 'safer' with shared_ptr.
For one thing, it does not feature what you just referred to as
"auto_ptr's 'destructive copy semantics'."
>Do 'custom deleters' relly enhance safety?
Maybe, but mainly that's part of the "more flexible behavior"
that I mentioned.
>Is it appropriate for a 'pointer' class (template) which is intended
to replace real pointes to internally allocate a counter for each
pointed-to object? (Real pointes are ultra-lightweight objects, like
an int).
Yes, it's appropriate. No, they don't replace all simple pointers.
Simple pointers are still appropriate for lightweight uses and where
they don't "own" anything.

Sep 23 '06 #69
On Sat, 23 Sep 2006 10:11:48 +0100 in comp.lang.c++, "Stuart
Golodetz" <sg*******@dNiOaSl.PpAiMpPeLxE.AcSoEmwrote,
>:) To quote from my previous post, "* Making things exception-safe is harder
with raw pointers." I think I should have made it more visible, I squeezed
it in at the bottom of the list.
Maybe you should use a list-in-first-out list.

Sep 23 '06 #70
Roland Pibinger wrote:
On 23 Sep 2006 03:58:31 -0700, "mlimber" <ml*****@gmail.comwrote:
Roland Pibinger wrote:
In general, you need ref-counting only when you _return_ 'ownership'
form a function (which is bad style anyway).
First, you need ref-counting when you share an object among other
objects whose destruction order is indeterminant. It allows you to
easily make sure you don't accidentally delete the object when it is
still needed.

I don't argue against RAII, quite the contrary. Just ref-counting
makes no sense when you don't return the object (any ref-counted
object, not just a shared_ptr).

void foo () {
shared_ptr<intsp (new int(0));
// assign sp to 100 other shared_ptrs
// pass sp to 100 fuunctions
} // here the ref_count of sp is 0
How about:

class A { ... };
class B { ... };

void Bar( A& a, B& b )
{
shared_ptr<intsp( new int(0) );
// ...
a.Use( sp );
b.Use( sp );
// sp is destroyed unless a or b retained a reference to it
}
In short, I don't think you have any real support for your own
home-grown principles of programming. RAII via smart pointers is
well-established, widely used, and recommended and practiced by all
recognized authorities on the language.

If I invented that principles I would be a genius ;-)
Of course, there are various sources that suggest that style of
programming - first and foremost the articulate stack-orientation in
the C++ language itself.
Your innovation is restricting yourself to using RAII without using
smart pointers, which the standard library provides explicitly for that
purpose.

Cheers! --M

Sep 23 '06 #71
Roland Pibinger wrote :
On 23 Sep 2006 11:18:21 +0100, Jens Theisen <jt***@arcor.dewrote:
>One last question: How do you return expensive objects, a
vector, say, from a function?
By value, of course.
Returning a pointer is an example of how people ridiculously use dynamic
allocation inappropriately.
>
void populate (std::vector<int>& vec) {
using namespace std;
vector<intloc;
loc.reserve (1000);
for (int i = 0; i < 1000; ++i) {
loc.push_back (i);
}
vec.swap (loc);
}
Or simply

std::vector<intpopulate()
{
using namespace std;
vector<intloc;
loc.reserve (1000);
for (int i = 0; i < 1000; ++i) {
loc.push_back (i);
}
return loc;
}

which has the same cost than a swap with move semantics and is even more
efficient with NRVO (available on any decent compiler)

Sep 23 '06 #72
"David Harmon" <so****@netcom.comwrote in message
news:45****************@news.west.earthlink.net...
On Sat, 23 Sep 2006 10:11:48 +0100 in comp.lang.c++, "Stuart
Golodetz" <sg*******@dNiOaSl.PpAiMpPeLxE.AcSoEmwrote,
>>:) To quote from my previous post, "* Making things exception-safe is
harder
with raw pointers." I think I should have made it more visible, I squeezed
it in at the bottom of the list.

Maybe you should use a list-in-first-out list.
Oh dear :) Programmer humour alert!
Sep 23 '06 #73
Jim Langston wrote :
Do you use smart pointers?
Not really, since I hardly even use dynamic allocation outside of
private parts of a class.
I especially avoid refcounting ones like shared_ptr, even though I have
nothing against objects using refcounting under the hood if they still
satisfy value semantics.

shared_ptr is used for many reasons, from which there are :
- Java-ish polymorphism heavy designs
- Resource management for objects which don't really have a
deterministic lifetime
- Avoidance of the overhead of copy semantics

For all of these usages, we can obviously see that shared_ptr is often
not the right solution.

Avoiding the overhead of copy semantics should be done by appropriate
use of references, by the compiler optimizing out temporaries, by the
usage of swap functions when relevant, and by move semantics, the new
feature introduced in C++0x, which will, hopefully, bring a great plus.

Objects that don't have a deterministic lifetime should use garbage
collection. Even though some people want garbage collection just because
they can't design software well, there are also some valid uses for it.
Shared_ptr is nothing but a poor replacement.

And for polymorphism, be it reasonable use or overuse ala Java (and
java-ish designs also often expect garbage collection), others tools
such as references, scoped_ptr, move_ptr or clone_ptr seem more fit.
clone_ptr should be usable for most things (and you could even use one
that uses refcounting under the hood) even though I think a smart
polymorphism object (and not pointer) is even better since it provides
more appropriate semantics.
Sep 23 '06 #74
loufoque <lo******@remove.gmail.comwrites:
Roland Pibinger wrote :
On 23 Sep 2006 11:18:21 +0100, Jens Theisen <jt***@arcor.dewrote:
One last question: How do you return expensive objects, a
vector, say, from a function?

By value, of course.
Returning a pointer is an example of how people ridiculously use
dynamic allocation inappropriately.
That's only possible in the special case where you construct the
object in the function returning it. If it's already there (accessed
through some of the parameters) and returned as-is, it will be copied.

I appreciate that it's not always the optimal solution. The OP,
however, didn't ask: Are smart pointers (or even _a_ particular smart
pointer) the answer to all problems, he asked if they are generally
used.

In this case, returning a vector rellying on NRVO is probably the best
thing to do, but returning by auto_ptr is also decent. Returning by
shared_ptr is still decent.

The only cost is a small runtime overhead, and please mind that
premature optimisation is the root of all evil. Also mind that not all
people have the time to make themselves familiar with all alternatives
there are. If you had to make compromises in what to make them
familiar with, would you compromise NRVO or shared_ptr?

shared_ptr is something that should be in the first chapter of any C++
tutorial.
which has the same cost than a swap with move semantics and is even
more efficient with NRVO (available on any decent compiler)
As a side note, shared_ptr will also benefit from move semantics,
won't it? At least I can't see a need for changing the refcount on
returning an rvalue shared_ptr anymore. That's not meant to be as an
argument in your specific example, where you were worrying about the
heap allocation cost.

Regards,

Jens
Sep 23 '06 #75
On 23 Sep 2006 19:33:05 +0100, Jens Theisen <jt***@arcor.dewrote:
>loufoque <lo******@remove.gmail.comwrites:
>By value, of course.
Returning a pointer is an example of how people ridiculously use
dynamic allocation inappropriately.

That's only possible in the special case where you construct the
object in the function returning it. If it's already there (accessed
through some of the parameters) and returned as-is, it will be copied.
In that special case there is even a workaround ...

// pray for RVO (or look up the compiler switch)
std::vector<intpopulate () {
...
}

int main() {
std::vector<intv;
populate().swap (v);
}

That's certainly not what I consider a good programming style. It
relies on a hack (RVO) and programs more to the implemenation than to
the interface.

Best wishes,
Roland Pibinger
Sep 24 '06 #76
loufoque posted:
Returning a pointer is an example of how people ridiculously use dynamic
allocation inappropriately.
The following code works perfectly:

#include <cstddef>
#include <cstring>
#include <cassert>

char *const PrependDriveLetter(char const letter, char const *const dir)
{
assert(dir);

std::size_t const len = std::strlen(dir);

char *const p = new char[len+3+1];

p[0] = letter; p[1] = ':'; p[2] = '\\';

memcpy(p+3,dir,len+1);

return p;
}

#include <iostream>
int main()
{
char const *const p = PrependDriveLetter('C',"Music\\Albums");

std::cout << p << '\n';

delete [] p;
}

--

Frederick Gotham
Sep 24 '06 #77
Frederick Gotham posted:
memcpy(p+3,dir,len+1);

std::memcpy(p+3,dir,len+1);

When the hell is g++ going to enforce this?!

--

Frederick Gotham
Sep 24 '06 #78
Frederick Gotham wrote :
The following code works perfectly:

What is returned is one of the argument, which is different from what I
had in mind.
Sep 24 '06 #79
Frederick Gotham wrote :
The following code works perfectly:
And it's also a perfect example of bad design.
Even C libraries stay away from this.

Sep 24 '06 #80
Frederick Gotham schrieb:
loufoque posted:
>Returning a pointer is an example of how people ridiculously use dynamic
allocation inappropriately.

The following code works perfectly:

#include <cstddef>
#include <cstring>
#include <cassert>

char *const PrependDriveLetter(char const letter, char const *const dir)
[...]

Ok, lets play "find the problems":

#include <cstddef>
#include <cstring>
char *const AppendPath(const char* const path, const char* const dir)
{
std::size_t pathlen = std::strlen(path);
std::size_t dirlen = std::strlen(dir);

if (path[pathlen-1] == '\\')
pathlen -= 1;

char* const str = new char[pathlen + dirlen + 2];

// new string: path + '\\' + dir + '\0';

memcpy(str, path, pathlen);
str[pathlen] = '\\';
memcpy(str+pathlen+1, dir, dirlen+1);

return str;
}

#include <iostream>
int main()
{
char* const path = AppendPath(AppendPath(
AppendPath("C:\\", "first"), "second"), "third");

std::cout << path << std::endl;
delete[] path;
}

Present this code to 100 C++ programmers, and with new/cout changed to
malloc/printf to another 100 C programmers. How many will find the problem(s)?

--
Thomas
http://www.netmeister.org/news/learn2quote.html
Sep 24 '06 #81
Thomas J. Gritzan posted:
Ok, lets play "find the problems":

Splendid. :)

#include <cstddef>
#include <cstring>
char *const AppendPath(const char* const path, const char* const dir)
{
std::size_t pathlen = std::strlen(path);
std::size_t dirlen = std::strlen(dir);

I would recommend defining dirlen as const.

if (path[pathlen-1] == '\\')
pathlen -= 1;

I would recommend putting the constant to the left of the equality
operator. (I'd also advocate use of the decrement operator).

if('\\' == path[pathlen-1]) --pathlen;

Actually, come to think of it, I'd probably go so far as the following in
order to enforce constness:

using std::size_t;

size_t const pathlen_ = std::strlen(path);

size_t const pathlen = pathlen_ - ('\\'==dir[pathlen_-1]);

(You might want to add two invertors before the open-parenthesis in order
to suppress a compiler warning.)

char* const str = new char[pathlen + dirlen + 2];

Let's assume for testing that:

path == "c:\\word\\"
dir == "personal"

In this case:

pathlen == 7 (after the decrement)
dirlen == 8

We now have a buffer 17 bytes long -- exactly right! I'd recommend
splitting the 2 into 1+1 though, it's more intuitive that way.

// new string: path + '\\' + dir + '\0';

memcpy(str, path, pathlen);

Absence of "std" qualifier, but OK other than that.

str[pathlen] = '\\';
memcpy(str+pathlen+1, dir, dirlen+1);

Absence of "std::" again, but OK.

return str;
}

#include <iostream>
int main()
{
char* const path = AppendPath(AppendPath(
AppendPath("C:\\", "first"), "second"), "third");

The pointer value returned by the primary and secondary invocations of
"AppendPath" are discarded, and so we've no way to deallocate the memory
allocated by them.

std::cout << path << std::endl;

I believe one is obliged to include <ostreamto make use of endl.

delete[] path;
}

Present this code to 100 C++ programmers, and with new/cout changed to
malloc/printf to another 100 C programmers. How many will find the
problem(s)?

If you select 100 programmers at random, then 5% will be expert
programmers, 15% will be proficient programmers, and 80% will be novices.

100% of the experts will remedy all problems.
85% of proficient programmers will remedy all problems.
9% of novices will rememdy all problems.

Therefore, it is wise to be concious of one's audience when code is to be
presented to other people.

--

Frederick Gotham
Sep 24 '06 #82
In article <ef**********@newsreader2.netcologne.de>,
Ph*************@gmx.de says...

[ ... ]
Ok, lets play "find the problems":
As the old saying goes, "REAL programmers can write FORTRAN in any
language", and IMO, this code is almost exactly that. At best it's
writing C in C++. C++ provides a perfectly good string class for
situations like this.
#include <cstddef>
#include <cstring>
char *const AppendPath(const char* const path, const char* const dir)
{
std::size_t pathlen = std::strlen(path);
std::size_t dirlen = std::strlen(dir);

if (path[pathlen-1] == '\\')
pathlen -= 1;

char* const str = new char[pathlen + dirlen + 2];

// new string: path + '\\' + dir + '\0';

memcpy(str, path, pathlen);
str[pathlen] = '\\';
memcpy(str+pathlen+1, dir, dirlen+1);

return str;
}
std::string append_path(std::string const &path, std::string const &dir)
{
std::string ret(path);
if (ret[ret.size()-1] != '\\')
ret += '\\';
ret += dir;
return ret;
}

Short, easy to understand, and virtually impossible to abuse into
leaking memory.
Present this code to 100 C++ programmers, and with new/cout changed to
malloc/printf to another 100 C programmers. How many will find the problem(s)?
Which problems? The memory leaks or the poor design or the lack of
exception safety, or ...? The next question would be who does a better
job of fixing the problems. My guess is that on the whole, the C++
programmers would do a better job of producing something like the
version above that's actually fairly robust and usable. This isn't a
matter of greater skill, but a matter of being provided tools that make
it relatively easy to do a decent job. In C you have to explicitly
manage all the memory, and explicitly free all the memory that's
allocated.

As in your example, calling free on a temporary object is essentially
impossible, meaning almost anything you do in C is relatively fragile.
Using a string class (nearly any string class, not just std::string)
makes more robust code relatively simple.

Of course, in C you can also pre-allocate the buffer and have the
function deposit the result in them:

void AppendPath(char const *path,
char const *dir,
char *result,
size_t res_length)
{
/* ... */
}

This at least prevents the obvious leak you showed, but still has major
problems. Consider, for example, if I have malice aforethought, and do
something like:

void my_exploit() {

char buffer[2];

AppendPath("A\\",
"address on the stack occupied by code I choose",
&buffer,
4096);
}

Now the code overwrites the stack frame and puts my code in place to be
executed. If AppendPath runs at a higher security level than my original
code, I've probably just breached security (in fact, code like this is a
common source of security problems).

Another method is somewhat similar, but instead of giving the address of
my own buffer (at all) what I put on the stack is the address of a
function followed by some parameters it gets called with. This is
typically done to call a function I can't call directly, or to pass
parameters that would be screened out as illegal if I called it directly
-- but if (for example) I specify an address inside of the function just
AFTER it checks parmeters...

--
Later,
Jerry.

The universe is a figment of its own imagination.
Sep 24 '06 #83

Yes. When possible I try to use the stack and pass objects via
references. But, after
that I use smart ptr's. Occasionally, when I need to link structures
together, I will use
a raw ptr as a backptr (ie has no ownership). Hope that helps.

Regards,
liam

Sep 25 '06 #84
rp*****@yahoo.com (Roland Pibinger) wrote:
>BTW, even gurus may change their mind
(http://www.gotw.ca/publications/index.htm):
"Most people have heard of the standard auto_ptr smart pointer
facility, but not everyone uses it daily. That's a shame, because it
turns out that auto_ptr neatly solves common C++ design and coding
problems, and using it well can lead to more robust code." Herb
Sutter, 1999

"Avoid using auto_ptr, instead use shared_ptr which is widely
available and being added to the standard library." Herb Sutter,
2004.
Of course, the main difference is that it became possible to recommend the
latter once we got more than just one smart pointer that fit the criteria
"is widely available and being added to the standard library." :-)

Herb

---
Herb Sutter (www.gotw.ca) (www.pluralsight.com/blogs/hsutter)

Convener, ISO WG21 (C++ standards committee) (www.gotw.ca/iso)
Architect, Developer Division, Microsoft (www.gotw.ca/microsoft)
Sep 25 '06 #85
liam_herron wrote:
[...] I use smart ptr's. Occasionally, when I need to link structures
together, I will use
a raw ptr as a backptr (ie has no ownership). Hope that helps.
In the case of std::tr1::shared_ptr, that's what std::tr1::weak_ptr is
for.

Cheers! --M

Sep 26 '06 #86

Thomas Tutone wrote:
Howard wrote:
And many of us don't have
Boost, so what's the alternative?

The FAQ includes a perfectly adequate intrusive smart pointer that I
have used for years:

http://www.parashift.com/c++-faq-lit...html#faq-16.22
Just had a look at that. Intrusive reference-counting and their
smart-pointers, with all your classes inheriting from one class was a
popular idiom in the late 1990s. It does have its merits but it can be
trickier to write them than you think.

One thing you can't do is forwardly declare that class X derives from
Y. You can forwardly declare X but you can't say it derives from Y
which means that, from within your template, you can have problems with
the casting or calling the virtual methods of your reference-counted
base-class if you want to keep your main class (X) only
forwardly-declared.
And why can't you use boost? Does your employer not permit it?
Don't be so surprised. Most companies have policies regarding 3rd party
open-source and unfortunately boost comes under this category. Over
here we do have boost, but I have run into problems having to get
approval for some other 3rd party open-source libraries I wanted to
use.

Remember that not everyone in the C++ world is so knowledgeable about
these things.
As my confusion above might illustrate, many of us probably just don't know
the best way to make regular use of smart pointers, or which one(s) to use.
Perhaps we just need a little nudge in the right direction...?

The FAQ will start you in the right direction. Jossuttis' The C++
Standard Library has some good examples of using a non-intrusive smart
pointer (using code supplied in the book) that works well with standard
containers.
I haven't looked at the recommendations but it's an old book and I
think smart-pointers have developed a lot since then. Scott Meyers had
an intrusive smart-pointer in Effective C++ which had many defects. I'm
sure he would write a much better one now, of course.

For any reference-counted smart-pointer (whether intrusive or
non-intrusive) you should be able to do the following:

- Have an instance of one for a class that is only forwardly-declared.
- Be able to pass in a custom deleter. (For intrusive, this is done by
calling a virtual method that makes it self-delete when appropriate,
rather than your smart-pointer calling delete on the class).
- Create a SHARED_PTR<Tfrom a SHARED_PTR<Uwhere SHARED_PTR is your
shared-pointer template and whenever U is derived from T or T is const
U. Not only that but if SHARED_PTR<Uhas a custom deleter then that
has to be passed into the SHARED_PTR<Tso your custom-deleter cannot
be a template class based on U that cannot convert to a template class
based on T.

Note: I have written such a smart-pointer but I borrowed a lot from
boost to do it. Years ago I wrote an intrusive one. Eventually
abandoned it.

Sep 26 '06 #87

Dave Steffen wrote:
Our main product is ~80k SLOC of highly mathematical C++; there's
not a bare pointer to be seen, except in the depths of some of the
math libraries (which are not for the faint of heart).
It is not the use or raw pointers that is the problem. My code uses
them when it wants to use references but can't. It uses smart-pointers
when it needs to control lifetime.

What you don't see in my code is delete statements. All the deletes are
carried out by the smart-pointers (well actually the underlying deleter
of the smart-pointer).

Of course you have to know that the object has a lifetime longer than
any raw pointer that points to it. When you know that to be the case
(and it is quite a significant amount of the time) then use a raw
pointer if you cannot use a reference, const if appropriate.

We switched
from raw pointers to Boost's shared pointer a while back, and
haven't had a memory leak since. We rely on them completely, and
have _never_ had a problem.

The only good reason _not_ to use them AFAIK is the memory overhead
of the ref count (which can be mitigated in several ways) and the
run-time overhead of the extra redirection. We estimate that the
run-time penalty in our application for using smart pointers is
around 2%. We may, in the future, have to do something about this,
but it's unlikely.
The redirection is likely to be optimised away by any decent compiler.
The run-time overhead comes in copying them. Now if you really do have
a situation where you have to control the reference count to ensure
that the object is only deleted when the last reference to it goes
away, then you would have to do that anyway manually.

If your only need for shared_ptr is to store in containers - boost has
a fairly new ptr_container set of containers now which can be used in
its place.

If you don't want to do that, then also remember that if you are
iterating through your containers, it is cheaper to use by-reference
than by-value so your algorithms, for example, can take operator() (
/*const*/ shared_ptr< T & ) rather than operator( shared_ptr< T )
and remember that const above is with respect to the pointer, not the T.

Sep 26 '06 #88
Earl Purple wrote:
Thomas Tutone wrote:
Howard wrote:
And many of us don't have
Boost, so what's the alternative?
The FAQ includes a perfectly adequate intrusive smart pointer that I
have used for years:

http://www.parashift.com/c++-faq-lit...html#faq-16.22

Just had a look at that. Intrusive reference-counting and their
smart-pointers, with all your classes inheriting from one class was a
popular idiom in the late 1990s. It does have its merits but it can be
trickier to write them than you think.
You're tearing down a straw man. The intrusive smart pointer in the
FAQ does not not involve any inheritance, let alone "all your classes
inheriting from one class." I described it as "perfectly adequate,"
and it is, at least for non-expert users trying to learn about smart
pointers.
One thing you can't do is forwardly declare that class X derives from
Y. You can forwardly declare X but you can't say it derives from Y
which means that, from within your template, you can have problems with
the casting or calling the virtual methods of your reference-counted
base-class if you want to keep your main class (X) only
forwardly-declared.
Since inheritance isn't involved, this isn't an issue.
And why can't you use boost? Does your employer not permit it?

Don't be so surprised.
Not to worry - I'm not surprised. That's why I asked, "does your
employer not permit it?"
Most companies have policies regarding 3rd party
open-source and unfortunately boost comes under this category. Over
here we do have boost, but I have run into problems having to get
approval for some other 3rd party open-source libraries I wanted to
use.

Remember that not everyone in the C++ world is so knowledgeable about
these things.
Agreed. In fact, I wondered if the OP simply didn't know that he could
download boost for free.
As my confusion above might illustrate, many of us probably just don't know
the best way to make regular use of smart pointers, or which one(s) to use.
Perhaps we just need a little nudge in the right direction...?
The FAQ will start you in the right direction. Jossuttis' The C++
Standard Library has some good examples of using a non-intrusive smart
pointer (using code supplied in the book) that works well with standard
containers.

I haven't looked at the recommendations but it's an old book and I
think smart-pointers have developed a lot since then. Scott Meyers had
an intrusive smart-pointer in Effective C++ which had many defects. I'm
sure he would write a much better one now, of course.
I fear you may have missed my point. The OP asked for advice about
"the best way to make regular use of smart pointers." I responded that
Josuttis' book - still the best treatise on the Standard Library - "has
some good examples of using a non-intrusive smart pointer (using code
supplied in the book) that works well with standard containers." I
wasn't advocating Josuttis' smart pointer, I was advocating his
examples of how to use smart pointers with the standard containers,
which is what the OP was seeking advice on. Sorry if you
misunderstood.

Best regards,

Tom

Sep 26 '06 #89

Thomas Tutone wrote:
You're tearing down a straw man. The intrusive smart pointer in the
FAQ does not not involve any inheritance, let alone "all your classes
inheriting from one class." I described it as "perfectly adequate,"
and it is, at least for non-expert users trying to learn about smart
pointers.
Let me describe why I don't think it is "perfectly adequate". Yes, it
will probably help you avoid leaks but breaks some other fundamental
rules. I'll ignore the possible implementation of operator=() using
swap and I'll assume Fred's constructor never throws.

======== the C++ FAQ writes:

class FredPtr;

class Fred {
public:
Fred() : count_(0) /*...*/ { } // All ctors set count_ to 0 !
...
private:
friend class FredPtr; // A friend class
unsigned count_;
// count_ must be initialized to 0 by all constructors
// count_ is the number of FredPtr objects that point at this
};

class FredPtr {
public:
Fred* operator-() { return p_; }
Fred& operator* () { return *p_; }
FredPtr(Fred* p) : p_(p) { ++p_->count_; } // p must not be NULL
~FredPtr() { if (--p_->count_ == 0) delete p_; }
FredPtr(const FredPtr& p) : p_(p.p_) { ++p_->count_; }
FredPtr& operator= (const FredPtr& p)
{ // DO NOT CHANGE THE ORDER OF THESE STATEMENTS!
// (This order properly handles self-assignment)
// (This order also properly handles recursion, e.g., if a
Fred contains FredPtrs)
Fred* const old = p_;
p_ = p.p_;
++p_->count_;
if (--old->count_ == 0) delete old;
return *this;
}
private:
Fred* p_; // p_ is never NULL
};
==============================

Now I gave 3 rules. This breaks all 2 of them even as it is.It will
break all 3 if we ever decide to make it a template.

(1) If I'm allowed to separate out the implementation of FredPtr from
its interface then I could have a FredPtr with Fred being incomplete.
Change all the above into a template though (assuming that any class
that uses it has to have an accessible count_, either public or by
making the template its friend). (I'm assuming we don't have export).
That's where the option of having Fred derive from a class (that
provides the count) come in as we could get away with only having that
class complete except that we can't forwardly declare that Fred derives
from it so it would probably require a hack with casting, unless anyone
knows of a better way (other than using non-intrusive reference
counting, which is the solution).

(2) Above implementation calls delete. No option for custom deleter.

(3). There is no equivalent for a "const Fred", i.e. a FredConstPtr or
whatever you might want to call it.

Of course there is an alternative to template - you can use
auto-code-generators. In fact these are often a viable alternative, for
example on embedded systems where templates are not permitted.
I fear you may have missed my point. The OP asked for advice about
"the best way to make regular use of smart pointers." I responded that
Josuttis' book - still the best treatise on the Standard Library - "has
some good examples of using a non-intrusive smart pointer (using code
supplied in the book) that works well with standard containers." I
wasn't advocating Josuttis' smart pointer, I was advocating his
examples of how to use smart pointers with the standard containers,
which is what the OP was seeking advice on. Sorry if you
misunderstood.
I will get my Josuttis out at some point when I'm home and have a look.
It may be good if the FAQ were to a "light" version of shared_ptr for
those that can't use boost for whatever reason. Such a version could be
copied and pasted from one file.

I actually think it would be advantageous for boost themselves to have
a "light" version of some of their libraries (i.e. one file no
dependencies).

Of course, even then you might have a problem relating to any copyright
statements at the top of files - will the company allow you to state
that you got the source from "open-source" (i.e. that the company
themselves do not actually own the copyrigth to this particular file).

Sep 26 '06 #90

Roland Pibinger wrote:
The C++ Standard library doesn't 'new' anything what has to be deleted
by the user and, vice versa, doesn't delete anything that has been
'newed' by the user (similar in C with malloc/free). The only
exception is auto_ptr (and shared_ptr in the future) which violates
that principle.
shared_ptr doesn't call delete on your class, it invokes your deleter.
But as a short-hand, they provided a default deleter for you in case
you didn't provide one. That default one calls delete on your class.

The purpose is not to prevent you from being able to do stupid things,
the purpose is to make it easier for you to write robust code.

If you want transfer-ownership in that you want to be able take the
control away from the shared_ptr, that can be done using the custom
deleter.

The problem, which is not a problem of shared_ptr but a problem of its
use, is that it is often overused, i.e. it is used in a scope where you
know that the lifetime of the object will exist, eg a functor written
like this on a collection of shared pointers:

return_type operator() ( shared_ptr< T ) /*const */
{
// do something and return whatever
}

of course you know here that there is no need to increase the reference
count on this shared pointer because the collection holding them will
still be there as long as your pointer to it is so

return_type operator() ( const shared_ptr< T & t_ptr) /* const */;
{
T & t = *t_ptr;
// do stuff with t. If you're doing just one call on it no need for
the above.
}

avoids an unnecessary copy of the shared_ptr (which isn't trivially
cheap, and would be done for every item in your collection).

You can, in the above, potentially make the function above a template
function on its argument. Thus:

template < typename T_PTR operator() ( T_PTR t_ptr );

etc. This now decouples the functor from the type of pointer your
collection is storing.

Still, you have to understand the developers out there. They are not
always bright enough to understand all of this and I'd rather see a few
unnecessary copies of shared_ptr in code I might have to maintain than
raw pointers everywhere. Optimise later where necessary.

Sep 26 '06 #91
Earl Purple wrote:
Thomas Tutone wrote:
You're tearing down a straw man. The intrusive smart pointer in the
FAQ does not not involve any inheritance, let alone "all your classes
inheriting from one class." I described it as "perfectly adequate,"
and it is, at least for non-expert users trying to learn about smart
pointers.

Let me describe why I don't think it is "perfectly adequate". Yes, it
will probably help you avoid leaks but breaks some other fundamental
rules. I'll ignore the possible implementation of operator=() using
swap and I'll assume Fred's constructor never throws.
[code snipped]
Now I gave 3 rules. This breaks all 2 of them even as it is.It will
break all 3 if we ever decide to make it a template.

(1) If I'm allowed to separate out the implementation of FredPtr from
its interface then I could have a FredPtr with Fred being incomplete.
Change all the above into a template though (assuming that any class
that uses it has to have an accessible count_, either public or by
making the template its friend). (I'm assuming we don't have export).
That's where the option of having Fred derive from a class (that
provides the count) come in as we could get away with only having that
class complete except that we can't forwardly declare that Fred derives
from it so it would probably require a hack with casting, unless anyone
knows of a better way (other than using non-intrusive reference
counting, which is the solution).

(2) Above implementation calls delete. No option for custom deleter.

(3). There is no equivalent for a "const Fred", i.e. a FredConstPtr or
whatever you might want to call it.

Of course there is an alternative to template - you can use
auto-code-generators. In fact these are often a viable alternative, for
example on embedded systems where templates are not permitted.

Let's cut to the chase here. You make some reasonable arguments here
that the FAQ intrusive smart pointer is a naive implementation and is
not perfect.

Here is my response. The relevant comparison for this discussion is
not to a perfect smart pointer. The comparison is to raw pointers.
The OP said that he doesn't use smart pointers, and a fair amount of
bandwidth was spent by various posters on how they don't "trust" smart
pointers.

I referred to the FAQ, which includes straight-forward,
easy-to-understand code. You reasonably point out various flaws in
that code. But if the choices are a naive smart pointer or a naive use
of raw pointers, I'm still going with the smart pointer. And the
advantage of the naive implementation is that a relatively
inexperienced C++ programmer can look at the code, understand it, and
learn from it. He or she may even be more comfortable using such code
than a black-box smart pointer that meets every requirement you place
on it.

So at the end of the day - for production code, I acknowledge your
points. For learning the wisdom of using smart pointers, I hope you
will at least consider - if not acknowledge - mine.

Best regards,

Tom

Sep 26 '06 #92

Thomas Tutone wrote:
Let's cut to the chase here. You make some reasonable arguments here
that the FAQ intrusive smart pointer is a naive implementation and is
not perfect.
Here is my response. The relevant comparison for this discussion is
not to a perfect smart pointer. The comparison is to raw pointers.
The OP said that he doesn't use smart pointers, and a fair amount of
bandwidth was spent by various posters on how they don't "trust" smart
pointers.
I referred to the FAQ, which includes straight-forward,
easy-to-understand code. You reasonably point out various flaws in
that code. But if the choices are a naive smart pointer or a naive use
of raw pointers, I'm still going with the smart pointer. And the
advantage of the naive implementation is that a relatively
inexperienced C++ programmer can look at the code, understand it, and
learn from it. He or she may even be more comfortable using such code
than a black-box smart pointer that meets every requirement you place
on it.
I would agree that, if you separated the implemention from the
interface in that class and write a swap function and implemented
operator= in terms of it then the class is usable, and might even have
some uses. One, for example, being if you are writing a library that
has a function that returns a newly created "Fred" and that you wanted
to return it as a reference-counted pointer. True that the class is not
a template but you might write a code-generator if you have many
classes like this and if it generated such code with the two changes
I've suggested, it would be reasonable enough in production code (might
not be thread-safe but I guess you could write a special version for
when that is required).

In fact I would rather 3rd party library providers did provide their
own smart pointers than either forcing me to install boost or loki or
whatever or even worse, telling me I have to delete something or call
some method or other when I've finished with something. Internally they
can implement their libraries using boost and I hope they would because
that would make their libraries less likely to leak.
So at the end of the day - for production code, I acknowledge your
points. For learning the wisdom of using smart pointers, I hope you
will at least consider - if not acknowledge - mine.
Not sure what code is written for if not as production code.

My point about that smart-pointer being in the FAQ is that many,
including myself, have treated that FAQ pretty much as a coding
standard guideline, and how could I tell another developer who started
using that smart-pointer above in code that it is not really fit for
use for a couple of reasons I have mentioned when they are likely to
answer that it must be good because it's in the official FAQ.

Sep 26 '06 #93

This discussion thread is closed

Replies have been disabled for this discussion.

By using this site, you agree to our Privacy Policy and Terms of Use.