To use or not to use smart pointers?

B

Boris

I had a 3 hours meeting today with some fellow programmers that are partly
not convinced about using smart pointers in C++. Their main concern is a
possible performance impact. I've been explaining the advantages of smart
pointers endlessly (which are currently used in all our C++ software; we
use the Boost smart pointers) as I'm seriously concerned that there is a
shift to raw pointers. We are not developing system software but rather
normal Windows programs (with exceptions turned on). I wouldn't want to
write a C++ program without smart pointers any more but after that endless
discussion I wonder if I'm too strict. Any serious arguments not to use
smart pointers?

Boris
 
V

Victor Bazarov

Boris said:
I had a 3 hours meeting today with some fellow programmers that are
partly not convinced about using smart pointers in C++. Their main
concern is a possible performance impact. I've been explaining the
advantages of smart pointers endlessly (which are currently used in
all our C++ software; we use the Boost smart pointers) as I'm
seriously concerned that there is a shift to raw pointers. We are not
developing system software but rather normal Windows programs (with
exceptions turned on). I wouldn't want to write a C++ program without
smart pointers any more but after that endless discussion I wonder if
I'm too strict. Any serious arguments not to use smart pointers?

There _is_ no performance impact. Whoever claims there is, should
prove it to you instead of just saying that. A smart pointer is just
a way for a programmer to relax and not have to remember when to
delete the object when the pointer goes out of scope. All access
to the actual object is resolved at compile time - no overhead.

V
 
D

Dennis Jones

Boris said:
I had a 3 hours meeting today with some fellow programmers that are partly
not convinced about using smart pointers in C++. Their main concern is a
possible performance impact. I've been explaining the advantages of smart
pointers endlessly (which are currently used in all our C++ software; we
use the Boost smart pointers) as I'm seriously concerned that there is a
shift to raw pointers. We are not developing system software but rather
normal Windows programs (with exceptions turned on). I wouldn't want to
write a C++ program without smart pointers any more but after that endless
discussion I wonder if I'm too strict. Any serious arguments not to use
smart pointers?

Oh my gosh, are you serious? No way. You are absolutely correct. The
benefits of smart pointers FAR outweigh any possible arguments against them.
There is no performance impact (that I know of), and the advantages
(automatic and correct object/resource lifetime management, avoidance of
memory leaks in the presence of exceptions, to name only two) are too
compelling to ignore. Another (strange, but typical) argument made against
smart pointers is their sometimes odd usage syntax (extra typing, ugliness?
I don't know), but in my view, that is a very small price to pay for the
peace of mind and safety afforded by their use.

If your collegues convince you otherwise, you should be working in another
field. If they won't listen to you about the benefits of smart pointers, go
work somewhere else where your position on the subject is appreciated (if
not required)!

- Dennis
 
K

Kai-Uwe Bux

Victor said:
There _is_ no performance impact. Whoever claims there is, should
prove it to you instead of just saying that. A smart pointer is just
a way for a programmer to relax and not have to remember when to
delete the object when the pointer goes out of scope. All access
to the actual object is resolved at compile time - no overhead.

With tr1::shared_ptr<>, I observed that the size of the smart pointer object
is twice as large as the size of a raw pointer (for two implementations, I
know). I actually doubt that one could to better and still have support for
the xxx_pointer_cast<> templates.

Although dereferencing is just as efficient as with raw pointers, you can
have an overhead in space; and you should expect an overhead in assignment
and copy operations that results from updating the reference count.

That said, I would doubt that the difference shows in measurements. I agree
that the person arguing in favor of raw pointers has the burden of proof
(and also should carry the burden of proving the correctness for the code
base resulting from a design decision in favor of raw pointers).


Best

Kai-Uwe Bux
 
M

Markus Schoder

There _is_ no performance impact. Whoever claims there is, should prove
it to you instead of just saying that. A smart pointer is just a way
for a programmer to relax and not have to remember when to delete the
object when the pointer goes out of scope. All access to the actual
object is resolved at compile time - no overhead.

boost::shared_ptr (or std::tr1::shared_ptr if you prefer) has a
significant performance overhead especially when being copied. There are
benchmarks at www.boost.org and I have also measured this myself.

The reasons are fairly obvious:

1. A boost::shared_ptr is larger than a plain pointer. It basically holds
two pointers -- one to the actual object the other to the reference
counter.
2. The reference counter needs to be incremented/decremented when the
smart pointer is copied/destroyed.
3. Locking is required to manipulate the reference counter for thread
safety.

Whether this all makes a difference in a given application is far from
obvious. I have switched an application that was extensively using a tree
structure built using boost::shared_ptr to boost::intrusive_ptr with a
significant performance gain.
 
D

Daniel T.

Boris said:
I had a 3 hours meeting today with some fellow programmers that are
partly not convinced about using smart pointers in C++. Their main
concern is a possible performance impact.

If they find an *actual* performance impact, then they have a leg to
stand on, until then their appeal to fear is fallacious.
I've been explaining the advantages of smart pointers endlessly
(which are currently used in all our C++ software; we use the Boost
smart pointers) as I'm seriously concerned that there is a shift to
raw pointers. We are not developing system software but rather
normal Windows programs (with exceptions turned on). I wouldn't want
to write a C++ program without smart pointers any more but after
that endless discussion I wonder if I'm too strict.

Why on earth would you want to write the same pointer management code
over, and over again? That's not reuse... Do these fellows also write a
loop instead of using strcpy? (I've known programmers who do that.)
Any serious arguments not to use smart pointers?

"The boss will yell at you and make you remove them."
 
D

Dave Steffen

Victor Bazarov said:
Boris said:
I had a 3 hours meeting today with some fellow programmers that are
partly not convinced about using smart pointers in C++. Their main
concern is a possible performance impact
[...]

There _is_ no performance impact. Whoever claims there is, should
prove it to you instead of just saying that. A smart pointer is
just a way for a programmer to relax and not have to remember when
to delete the object when the pointer goes out of scope. All access
to the actual object is resolved at compile time - no overhead.

And by the way, I verified this experimentally last week while
profiling some code. Using GCC 4.0.4 and Boost 1.33.1, it looks like
there's a very small amount of overhead (like 5%) in executables built
in "debug" mode, e.g. no optimization, no inlining, etc. This
overhead *completely* dissapears when the optimization levels are turned
up.

So:

A) Even if there is some small performance impact, it's well worth
the *programmer* time you save developing and debugging your
code;

B) There isn't any performance impact when building executables for
real use, just as Victor says; and

C) This is easy to prove, so you don't have to take our word for it;
go do the experiment on your machine, with your compiler.

And by the way, we use smart pointers *everywhere*, and it's probably
saved us *years* of programmer time.

--
Dave Steffen, Ph.D. "I say we invite opportunity inside
Software Engineer IV for a nice cup of tea, then hit her
Numerica Corporation on the head and steal her purse."
ph (970) 461-2000 x227
dgsteffen numerica us -- Shlock Mercenary
 
M

Martijn van Buul

* Dennis Jones:
There is no performance impact (that I know of), and the advantages
(automatic and correct object/resource lifetime management,

Automatic? Yes. Correct ? In your wildest dreams.
If your collegues convince you otherwise, you should be working in another
field. If they won't listen to you about the benefits of smart pointers, go
work somewhere else where your position on the subject is appreciated (if
not required)!

I really don't know what gave you the right to speak so harshly without even
remotely knowing the context. Boost::shared_ptr (or boost::whatever) is
_NOT_ the holy grail, and most definately NOT always applicable.
 
D

Dennis Jones

Martijn van Buul said:
* Dennis Jones:

Automatic? Yes. Correct ? In your wildest dreams.

Okay, how about when used correctly?

I really don't know what gave you the right to speak so harshly without
even
remotely knowing the context. Boost::shared_ptr (or boost::whatever) is
_NOT_ the holy grail, and most definately NOT always applicable.

I certainly didn't mean to be "harsh." I just find it hard to justify NOT
using them for any reason. I have personally developed an application that
has benefited greatly from using smart pointers almost (if not completely)
exclusively, which would have been a nightmare to develop and maintain
otherwise. And for me, that's enough of a reason to be a strong proponent.

I'm not an expert, for sure, but I can't think of a case where they would
not be applicable. Care to enlighten the unenlightened?

- Dennis
 
M

Martijn van Buul

* Dennis Jones:
I'm not an expert, for sure, but I can't think of a case where they would
not be applicable. Care to enlighten the unenlightened?

I work in computer vision. Not too long ago, I was rewriting some of our
existing codebase. The algorithms itself were OK, but the implementation was
"C with classes" and no longer up to par.

One stood out in particular: A simple data structure used to identify objects
in a bitmap image, consisting of a doubly linked list of begin- and end points
for each row. This particular algorithm identified all connected objects in a
structure like this, and the existing implementation used a pool of these
critters, and was reasonably fast. ~ 200 microseconds per image, on my
computer, with my test set. (Using the same CPU and same compiler (gcc 4.2.0)
for all cases)

I first rewrote it to a std::list<CSegment>, with CSegment being something
like

struct CSegment
{
int mStart;
int mEnd;
int mRow;
};

Performance was abysmal; execution time went up to a staggering 50 ms. That's
more than the total budget I have for the *entire* evaluation process per
image, so it's not even close to acceptable.

I then rewrote it to a smart_ptr approach, by giving each CSegment a

boost::shared_ptr<CSegment> mNext
boost::weak_ptr<CSegment> mPrev

The reasoning behind this was that I *know* std::list does more checking
than I really needed, but I would like to have the protection against
memory leaks.

Performance dropped slightly, but not enough (40 ms). Not even close.

I then rewrote things to a plain jane new/delete fest, using normal
pointers. Execution time went down to 20 ms. Using a class-specific operator
new/delete, which used manually operated storage, took it down to 2 ms.
Ditching the operator new/delete, and using inline routines to do allocation
/release of segments got it down to its original 200 us. Inspection of the
resulting assembly yielded that it would save about two calls per allocation/
release.

So there you have it. boost::shared_ptr sucks for this application.
std::list sucks for this application. Nifty C++ like overloading operator new
is not good enough. The difference between "50 ms" and "200 us" is the
difference between "No product" and "something we can make profit out of".

Does this mean that boost::shared_ptr (or std::list, or... ) is bad? Hell no.
It works great, and can lead to very nice and elegant solutions. Claiming that
boost::shared_ptr should be avoided just because of situations like this
is plain stupid - exactly as stupid as asserting boost::shared_ptr is
better than using new/delete in each and every case.

Real life isn't that simple.
 
M

Martijn van Buul

* Victor Bazarov:
A smart pointer is just a way for a programmer to relax and not have to
remember when to delete the object when the pointer goes out of scope.

If a programmer wants to relax and don't bother to think about how his/her
code is going to work out, then _by all means_ go have a holiday.
 
R

Roland Pibinger

boost::shared_ptr (or std::tr1::shared_ptr if you prefer) has a
significant performance overhead especially when being copied. There are
benchmarks at www.boost.org and I have also measured this myself.

The reasons are fairly obvious:

1. A boost::shared_ptr is larger than a plain pointer. It basically holds
two pointers -- one to the actual object the other to the reference
counter.
2. The reference counter needs to be incremented/decremented when the
smart pointer is copied/destroyed.
3. Locking is required to manipulate the reference counter for thread
safety.

4. The reference counter of shared_ptr must be dynamically allocated.
This means one extra dynamic allocation for each pointed-to object.

5. 'Smart pointers' introduce semantic anomalies, e.g. auto_ptr uses
'destructive copy semantics'. 'Smart pointers' cannot completely
emulate real pointer behavior.

6. 'Smart pointers' foster a heap-oriented programming style ('Java in
C++').

In sum, the disadvantages of 'smart pointers' by far outweigh their
advantages.
 
M

Michael DOUBEZ

Roland Pibinger a écrit :
4. The reference counter of shared_ptr must be dynamically allocated.
This means one extra dynamic allocation for each pointed-to object.

Use boost::intrusive_ptr.
5. 'Smart pointers' introduce semantic anomalies, e.g. auto_ptr uses
'destructive copy semantics'. 'Smart pointers' cannot completely
emulate real pointer behavior.

use boost::scoped_ptr instead of auto_ptr to avoid the copy problem.
6. 'Smart pointers' foster a heap-oriented programming style ('Java in
C++').

You mean 'shared_ptr' foster ...
auto_ptr, scoped_ptr and intrusive_ptr are on the stack.
In sum, the disadvantages of 'smart pointers' by far outweigh their
advantages.

That depends. If what you need is reference counting (shared_ptr) then
any other reference counting system you may use will fare more or less
the same. The alternatives are :
- tracking down the livetime of object
- using garbage collecting

If you don't need it and just want to insure your pointer is destroyed
when going out of scope, use boost::scoped_ptr or std::auto_ptr (with
cautions) and then the performance overhead should be minimal.

Michael
 
M

Michael DOUBEZ

Daniel T. a écrit :
If they find an *actual* performance impact, then they have a leg to
stand on, until then their appeal to fear is fallacious.


Why on earth would you want to write the same pointer management code
over, and over again? That's not reuse... Do these fellows also write a
loop instead of using strcpy? (I've known programmers who do that.)


"The boss will yell at you and make you remove them."

That reminded me of an ACCU article about developpers, monkeys and
cultural transmission:
http://accu.org/index.php/journals/290

This article could help as a starter for exception safety through smart
pointers:
http://accu.org/index.php/journals/298

Michael
 
R

Roland Pibinger

Roland Pibinger a écrit :

Use boost::intrusive_ptr.

I prefer non-intrusive, zero-overhead real pointers. Why accept
anything less?
use boost::scoped_ptr instead of auto_ptr to avoid the copy problem.

I prefer objects on the stack. Like many other 'smart pointers'
scoped_ptr is a solution desperately looking for a problem.
You mean 'shared_ptr' foster ...
auto_ptr, scoped_ptr and intrusive_ptr are on the stack.

But the pointed-to objects are not. The urge to use 'smart pointers'
typically pops up when (pointers to) objects shall be returned from a
function. This 'factory style' is characteristic for Java programming
and contrasts with RAII style of programming in C++ that binds
resources to one scope.
The alternatives are :
- tracking down the livetime of object
- using garbage collecting

The alternative is RAII. Let a local object manage both, acquisition
and release of (a) resource(s).
 
M

Michael DOUBEZ

Roland Pibinger a écrit :
I prefer non-intrusive, zero-overhead real pointers. Why accept
anything less?

If that fits your need, doesn't cause ressource leak and make the code
clear. No reason.

Not everybody needs reference counting.
I prefer objects on the stack. Like many other 'smart pointers'
scoped_ptr is a solution desperately looking for a problem.

I also prefer object on the stack but when you cannot have them on the
stack which can hapen in non-functionnal-style programming or under
specific environment (cooperative OS by example).
But the pointed-to objects are not.

Then why do you need smart pointers ? Indeed, if the objects are on the
stack, do not use smart pointers and even why use pointer at all except
for function calls requiring a pointer.
The urge to use 'smart pointers'
typically pops up when (pointers to) objects shall be returned from a
function.

Strong exception guaranty is a good reason. Confidence (i.e. let the
compiler destroy my dynamically allocated pointer for me in my class) is
another. And in some case, it is hard to determine/track who should be
the owner of a ressource.
This 'factory style' is characteristic for Java programming
and contrasts with RAII style of programming in C++ that binds
resources to one scope.

Factory may be misused/overused as any other pattern but is still useful
even in C++.
The alternative is RAII. Let a local object manage both, acquisition
and release of (a) resource(s).

Do you advocate to create a specific RAII class for each ressource you
define ? I do no find it practical when a simple boost::scoped_ptr(new
Object()); do it for me.

Michael
 
T

Tim H

There _is_ no performance impact. Whoever claims there is, should
prove it to you instead of just saying that.

Not true! All the refcounting has a real cost. It doesn't stop me
from using them everywhere, though I have some other slight gripes
about them.
 
G

Glen Dayton

Michael said:
Daniel T. a écrit :

Just because you have difficulty measuring it doesn't mean it
doesn't exist. Most projects overuse shared_ptr<>. You need to
use an appropriate mix of auto_ptr<> and shared_ptr<>.

std::auto_ptr<> has no performance overhead, but
boost::share_ptr<> necessarily internally needs a
synchronization object or interlocked increment. In a
multi-core CPU environment the lock or interlocked increment
operation requires the processor cache to be flushed so that the
change is visible to other cores. This performance hit can be
difficult to detect because no profiler outside of a hardware
logic analyzer can really detect it. You'll need to compare
performance with raw pointer code for the same tasks.

Despite this peanut butter spread of a performance penalty,
you'd be insane to use raw pointers. If you habitually use raw
pointers you might as well be programming in C. Used
appropriately, auto_ptr<>, shared_ptr<>, weak_ptr<>, and
brethren will eliminate all resource leaks and their attendant
problems such as memory corruption through premature frees. Raw
unwrapped pointers provide no protection. Naked pointers are
obscene.
That reminded me of an ACCU article about developpers, monkeys and
cultural transmission:
http://accu.org/index.php/journals/290

This article could help as a starter for exception safety through smart
pointers:
http://accu.org/index.php/journals/298

Michael

Rather than habitually using shared_ptr<>, consider using the
boost smart containers. Use auto_ptr<> as much as possible to
avoid sharing. Consider that shared objects are another form of
global information that violates encapsulation in the time
domain. Use shared_ptr<> when you need to but use auto_ptr<>
when you really mean to transfer ownership.

Glen
 
D

Dennis Jones

So there you have it. boost::shared_ptr sucks for this application.
std::list sucks for this application. Nifty C++ like overloading operator
new
is not good enough. The difference between "50 ms" and "200 us" is the
difference between "No product" and "something we can make profit out of".

Does this mean that boost::shared_ptr (or std::list, or... ) is bad? Hell
no.
It works great, and can lead to very nice and elegant solutions. Claiming
that
boost::shared_ptr should be avoided just because of situations like this
is plain stupid - exactly as stupid as asserting boost::shared_ptr is
better than using new/delete in each and every case.

I see. Thanks for sharing that. I had no idea performance could be so
negatively affected. Thankfully, my application is not nearly as affected
by the performance penalties you site. While it needs to perform well, my
application doesn't allocate that much memory, and its performance
requirements are not even close to what yours apparently are. Also, I only
use shared_ptr when I need it for its reference counting ability (and
sometimes for the custom deleter, and in those cases, performance isn't even
an issue). Otherwise I use the much simpler scoped_ptr.

- Dennis
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top