I didn't find information about performance issues with auto_ptr and shared_ptr(I use tr1 implementation). As shared_ptr is more complicated compared to auto_ptr so auto_ptr is faster? So in general question sounds like what can you say about performance of shared_ptr with comparison with auto_ptr?
PS: I know that now unique_ptr is preferable than auto_ptr, but not all compilers support it, so question is about auto_ptr and shared_ptr
When dereferencing there are no performance differences.
If you allocate your shared_ptr's with make_shared you don't waste any heap allocations.
When copying the pointer (not the object), a shared_ptr is a little bit slower because it needs to increase it's reference counter.
However, these probably does not matter, so stick with shared_ptr combined with make_shared.
auto_ptr is a deprecated C++98 construct. As such, any performance benefit it might have is far outweighed by the fact that you shouldn't use it anymore in newly-written C++11 code, and instead badger the compiler / library maintainers to implement support for unique_ptr.
That being said, use what semantically fits your use case, unless you have profiled that you have a problem with *_ptr...
As with all performance issues: you need to measure it for yourself in your particular setup.
In general, though, you can expect some more overhead for a shared_ptr<> than for auto_ptr<> as it has to do some more work behind the scene to ensure proper shared behavior for the enclosed pointer.
On the other hand, the two are not really comparable: auto_ptr<> supports only one copy (the ownership is transfered on copy), while shared_ptr<> supports multiple copies. So unless you only use the above pointers for one copy-pointer, you cannot make a meaningful comparision. If you do use one-copy pointer and you are sure you will not need more copies, use the specialized auto_ptr<>.
In any case, whether the performance differences are significant depends on your particular project.
In general the only good answer is to measure.
But for this case you know that shared_ptr, unless you're using make_shared it involves a dynamic allocation of a counter block, and unless you have a really good small objects allocator, it's bound to be really slow (talking orders of magnitude) to create the first shared pointer to an object.
But then, perhaps with Boost and the standard library that allocation is really optimized. And maybe, probably!, you can use make_shared to use just 1 allocation for both the object and its control block. So … measure.
By the way, auto_ptr is deprecated.
With any modern compiler use unique_ptr instead.
Related
I'm a little bit confused about the main use of std::unique/shared_ptr(std::vector<>) when I can simply use a std::vector<>, which, as I know, is itself inherently a dynamic array. As I have also seen around, people say that there is no any performance difference between these two. So, based on all this, what is the point of using a smart pointer pointing to a container (in this case, a vector) instead of a vector alone?
First of all, you shouldn't be using std::shared_ptr unless you need the specific "shared ownership" semantics associated with std::shared_ptr. If you need a smart pointer, you should default to std::unique_ptr by default, and only switch away from it in the scenario where you expressly find that you need to.
Secondly: ostensibly, the reason to prefer std::unique_ptr<TYPE> over TYPE is if you plan to move the object around a lot. This is the common design paradigm for large objects that are either unmovable, or otherwise expensive to move—i.e. they implemented a Copy Constructor and didn't implement a Move Constructor, so moves are forced to behave like a Copy.
std::vector, however, does have relatively efficient move semantics: if you move a std::vector around, regardless of how complex its contained types are, the move only constitutes a couple of pointer swaps. There's no real risk that moving a std::vector will incur a large amount of computational complexity. Even in the scenario where you're overriding a previously allocated array (invoking the Destructors of all objects in the vector), you'd still have that complexity if you were using std::unique_ptr<std::vector<TYPE>> instead, saving you nothing.
There are two advantages to std::unique_ptr<std::vector<TYPE>>. The first of which is that it gets rid of the implicit copy constructor; maybe you want to enforce to maintaining programmers that the object shouldn't be copied. But that's a pretty niche use. The other advantage is that it allows you to stipulate the scenario where there's no vector, i.e. vec.size() == 0 is a different condition than doesNotExist(vec). But even in that scenario, you should be preferring std::optional<std::vector> instead, which better conveys through the code the intent of the object. Granted, std::optional is only available in C++17→ Code, so maybe you're in an environment that hasn't implemented it yet. But otherwise, there's little reason to use std::unique_ptr<std::vector>.
So in general, I don't believe there are practical uses for std::unique_ptr<std::vector>. There's no practical performance difference between it and std::vector, and using it will just make your code needlessly complex.
I've been making some objects using the pimpl idiom, but I'm not sure whether to use std::shared_ptr or std::unique_ptr.
I understand that std::unique_ptr is more efficient, but this isn't so much of an issue for me, as these objects are relatively heavyweight anyway so the cost of std::shared_ptr over std::unique_ptr is relatively minor.
I'm currently going with std::shared_ptr just because of the extra flexibility. For example, using a std::shared_ptr allows me to store these objects in a hashmap for quick access while still being able to return copies of these objects to callers (as I believe any iterators or references may quickly become invalid).
However, these objects in a way really aren't being copied, as changes affect all copies, so I was wondering that perhaps using std::shared_ptr and allowing copies is some sort of anti-pattern or bad thing.
Is this correct?
I've been making some objects using the pimpl idiom, but I'm not sure whether to used shared_ptr or unique_ptr.
Definitely unique_ptr or scoped_ptr.
Pimpl is not a pattern, but an idiom, which deals with compile-time dependency and binary compatibility. It should not affect the semantics of the objects, especially with regard to its copying behavior.
You may use whatever kind of smart pointer you want under the hood, but those 2 guarantee that you won't accidentally share the implementation between two distinct objects, as they require a conscious decision about the implementation of the copy constructor and assignment operator.
However, these objects in a way really aren't being copied, as changes affect all copies, so I was wondering that perhaps using shared_ptr and allowing copies is some sort of anti-pattern or bad thing.
It is not an anti-pattern, in fact, it is a pattern: Aliasing. You already use it, in C++, with bare pointers and references. shared_ptr offer an extra measure of "safety" to avoid dead references, at the cost of extra complexity and new issues (beware of cycles which create memory leaks).
Unrelated to Pimpl
I understand unique_ptr is more efficient, but this isn't so much of an issue for me, as these objects are relatively heavyweight anyway so the cost of shared_ptr over unique_ptr is relatively minor.
If you can factor out some state, you may want to take a look at the Flyweight pattern.
If you use shared_ptr, it's not really the classical pimpl
idiom (unless you take additional steps). But the real question
is why you want to use a smart pointer to begin with; it's very
clear where the delete should occur, and there's no issue of
exception safety or other to be concerned with. At most,
a smart pointer will save you a line or two of code. And the
only one which has the correct semantics is boost::scoped_ptr,
and I don't think it works in this case. (IIRC, it requires
a complete type in order to be instantiated, but I could be
wrong.)
An important aspect of the pimpl idiom is that its use should be
transparent to the client; the class should behave exactly as if
it were implemented classically. This means either inhibiting
copy and assignment or implementing deep copy, unless the class
is immutable (no non-const member functions). None of the usual
smart pointers implement deep copy; you could implement one, of
course, but it would probably still require a complete type
whenever the copy occurs, which means that you'd still have to
provide a user defined copy constructor and assignment operator
(since they can't be inline). Given this, it's probably not
worth the bother using the smart pointer.
An exception is if the objects are immutable. In this case, it
doesn't matter whether the copy is deep or not, and shared_ptr
handles the situation completely.
When you use a shared_ptr (for example in a container, then look this up and return it by-value), you are not causing a copy of the object it points to, simply a copy of the pointer with a reference count.
This means that if you modify the underlying object from multiple points, then you affect changes on the same instance. This is exactly what it is designed for, so not some anti-pattern!
When passing a shared_ptr (as the comments say,) it's better to pass by const reference and copy (there by incrementing the reference count) where needed. As for return, case-by-case.
Yes, please use them. Simply put, the shared_ptr is an implementation of smart pointer. unique_ptr is an implementation of automatic pointer:
Occasionally, for fleeting moments, I think auto_ptr is cool. But most of the time I recognize that there are much simpler techniques that make it irrelevant. For example, if I want to have an object freed automatically, even if an exception is thrown, I could new up the object and assign to an auto_ptr. Very cool! But I could have more easily created my object as a local variable, and let the stack take care of it (duh!).
Thus I was not too surprised when I found google C++ coding standards banning the use of auto_ptr. Google states that scoped_ptr should be used instead (if a smart pointer is needed).
I'd like to know if anyone, contrary to my experience, can give a solid reason(s) of when auto_ptr is the best or simplest thing to use. If not, then I suppose I will ban using it myself (following google's lead).
update: For those who expressed concern, no I am not adopting google standards. For example, against google advice, I agree exception-handling should be activated. I also like using preprocessor macros, such as the printable enum I made. It is just the auto_ptr topic that struck me.
update2: It turns out my answer comes from two of the responders below, and a note from Wikipedia. First, Herb Sutter did show a valid use (source-sink idiom and lifetime-linked object composition). Second, there are shops where TR1 and boost are not available or banned and only C++03 is allowed. Third, according to Wikipedia, the C++0x spec is deprecating auto_ptr and replacing it with unique_ptr. So my answer is: use unique_ptr if available to me (on all platforms in consideration) else use auto_ptr for the cases that Sutter depicts.
It's the simplest thing to use when you need a scoped or unique pointer and you are working in a strict C++03 environment with no access to a tr1 implementation or boost.
Herb Sutter can help you out on this one: http://www.drdobbs.com/184403837
While banning auto_ptr seems attractive, but there is one issue:
template <typename T>
some_smart_ptr<T> create();
What will you replace the some_smart_ptr placeholder with ?
The generic answer, shared_ptr, is only worth it if the ownership is truly shared, if the function grants the caller exclusive ownership of the resources, it's misleading at best (and a typical case of premature pessimization as far as I am concerned).
On the other hand, in C++03, no other form of smart pointer can deliver: it's impossible, without move semantics, to provide what we'd like here. auto_ptr or a naked pointer are the two logical contenders. But then a naked pointer exposes you to the risk of leaks if the caller is careless.
With C++0x, unique_ptr advantageously replace auto_ptr in every situation.
std::auto_ptr still has pointer semantics, so automatic (non-pointer) variables aren't a substitute. In particular, std::auto_ptr supports polymorphism and re-assignment. With stack variables you can use references for polymorphism, but references don't allow for re-assignment.
Sometimes std::auto_ptr will do just fine. For example, for implementing a pimpl. True, in the vast majority of cases boost' smart pointer library offers better choices for a smart pointer. But right now std::auto_ptr is a standard solution, whereas boost's smart pointers aren't.
Using auto_ptr as function return value you will enjoy no copiyng overhead and never have memory leak. std::auto_ptr<obj> foo() can be safely called in { foo(); } while obj *foo() cannot. boost::shared_ptr can solve this, but with higher overhead.
Also, some objects can't be created on stack because of memory constraints: thread stacks are relatively small. But boost::scoped_ptr is better in this case since it can't be accidentally released.
Well one reason would be that scoped_ptr is non-copyable, so it's safer to use and harder to make mistakes with. auto_ptr allows transfer of ownership (eg. by passing it another auto_ptr as a constructor parameter). If you need to think things like transferring the ownership, the chances are you're better off with a smart pointer like shared_ptr.
I am learning about smart pointers (std::auto_ptr) and just read here and here that smart pointers (std::auto_ptr) should not be put in containers (i.e. std::vector) because even most compilers won't complain and it might seem correct. There is no rule that says smart pointers won't be copied internally (by vector class for example) and transfer its ownership, then the pointer will become NULL. In the end, everything will be screwed up.
In reality, how often does this happen?
Sometimes I have vectors of pointers and if in the future I decide I want to have a vector of smart pointers what would my options?
I am aware of C++0x and Boost libraries, but for now, I would prefer to stick to a STL approach.
Yes, you really can't use std::auto_ptr with standard containers. std::auto_ptr copies aren't equivalent, and because standard containers (and algorithms) are allowed to copy their elements at will this screws things up. That is, the operation of copying a std::auto_ptr has a meaning other than a mere copy of an object: it means transferring an ownership.
Your options are:
Use the Boost Smart Pointers library. This is arguably your best option.
Use primitive pointers. This is fast and safe, so long as you manage the pointers properly. At times this can be complex or difficult. For example, you'll have to cope with (avoid) double-delete issues on your own.
Use your own reference-counting smart pointer. That'd be silly; use a Boost Smart Pointer.
The problem you are referring to concerns auto_ptr since it moves ownership on copy. shared_ptr and unique_ptr work just fine with containers.
Any type that you use with a standard container template must conform with the requirements for that container. In particular, the type must satisfy the requirements for CopyConstructible and Assignable types.
Many smart pointers do satisfy these requirements and may be used with standard containers but std::auto_ptr is not one of them because copies of std::auto_ptr are not equivalent to the source that they were created or assigned from.
Although some implementations of standard container may work with auto_ptr in some situations it is dangerous to rely on such implementation details.
theoretically you can use std::auto_ptr with STL containers if you completely understand their internal implementation and don't do anything that can lose auto_ptr ownership, but practically it's much more safe to use containers with raw ptrs.
"In reality, how often does this happen?" - is very dangerous question by itself. first of all, STL - it's not a single standard implementation, there're many. Each one can implement containers in different ways, so your highly tuned code to avoid all "auto_ptr in containers" mines can burst switching to another STL implementation. Also, your code maintenance will be highly complicated, any correctly looking change to your code can break your program. how can you remember that or force others maintainers to remember? putting warnings in any place where such changes can occur? impossible.
so, conclusion: it's just a bad idea that brings nothing but headache
For classes that have an auto ptr data member, I always have a clone method that returns a new auto ptr. I then implement an assignment method and copy constructor that call the clone method (and never the default assignment operator of auto ptr). This way you can safely use the class in STL containers.
In the actual C++ standard, creating collections satisfying following rules is hard if not impossible:
exception safety,
cheap internal operations (in actual STL containers: the operations are copies),
automatic memory management.
To satisfy (1), a collection can't store raw pointers. To satisfy (2), a collection must store raw pointers. To satisfy (3), a collection must store objects by value.
Conclusion: the three items conflict with each other.
Item (2) will not be satisfied when shared_ptrs are used because when a collection will need to move an element, it will need to make two calls: to a constructor and to a destructor. No massive, memcpy()-like copy/move operations are possible.
Am I correct that the described problem will be solved by unique_ptr and std::move()? Collections utilizing the tools will be able to satisfy all 3 conditions:
When a collection will be deleted as a side effect of an exception, it will call unique_ptr's destructors. No memory leak.
unique_ptr does not need any extra space for reference counter; therefore its body should be exact the same size, as wrapped pointer,
I am not sure, but it looks like this allows to move groups of unique_ptrs by using memmove() like operations (?),
even if it's not possible, the std::move() operator will allow to move each unique_ptr object without making the constructor/destructor pair calls.
unique_ptr will have exclusive ownership of given memory. No accidental memory leaks will be possible.
Is this true? What are other advantages of using unique_ptr?
I agree entirely. There's at last a natural way of handling heap allocated objects.
In answer to:
I am not sure, but it looks like this allows to move groups of unique_ptrs by using memmove() like operations,
there was a proposal to allow this, but it hasn't made it into the C++11 Standard.
Yes, you are right. I would only add this is possible thanks to r-value references.
When a collection will be deleted as a side effect of an exception, it will call unique_ptr's destructors. No memory leak.
Yes, a container of unique_ptr will satisfy this.
unique_ptr does not need any extra space for reference counter; therefore its body should be exact the same size, as wrapped pointer
unique_ptr's size is implementation-defined. While all reasonable implementations of unique_ptr using it's default destructor will likely only be a pointer in size, there is no guarantee of this in the standard.
I am not sure, but it looks like this allows to move groups of unique_ptrs by using memmove() like operations (?),
Absolutely not. unique_ptr is not a trivial class; therefore, it cannot be memmoved around. Even if it were, you can't just memmove them, because the destructors for the originals need to be called. It would have to be a memmove followed by a memset.
even if it's not possible, the std::move() operator will allow to move each unique_ptr object without making the constructor/destructor pair calls.
Also incorrect. Movement does not make constructors and destructors not be called. The unique_ptr's that are being destroyed need to be destroyed; that requires a call to their destructors. Similarly, the new unique_ptrs need to have their constructors called; that's how an object's lifetime begins.
There's no avoiding that; it's how C++ works.
However, that's not what you should be worried about. Honestly, if you're concerned about a simple constructor/destructor call, you're either in code that you should be hand-optimizing (and thus writing your own code for), or you're prematurely optimizing your code. What matters is not whether constructors/destructors are called; what matters is how fast the resulting code is.
unique_ptr will have exclusive ownership of given memory. No accidental memory leaks will be possible.
Yes, it will.
Personally, I'd say you're doing one of the following:
Being excessively paranoid about copying objects. This is evidence by the fact that you consider putting a shared_ptr in a container is too costly of a copy. This is an all-too-common malady among C++ programmers. That's not to say that copying is always good or something, but obsessing over copying a shared_ptr in a container is ridiculous outside of exceptional circumstances.
Not aware of how to properly use move semantics. If your objects are expensive to copy but cheap to move... then move them into the container. There's no reason to have a pointer indirection when your objects already contain pointer indirections. Just use movement with the objects themselves, not unique_ptrs to objects.
Disregarding the alternatives. Namely, Boost's pointer containers. They seem to have everything you want. They own pointers to their objects, but externally they have value semantics rather than pointer semantics. They're exception safe, and any copying happens with pointers. No unique_ptr constructor/destructor "overhead".
It looks like the three conditions I've enumerated in my post are possible to obtain by using Boost Pointer Container Library.
This question illlustrates why I so love the Boehm garbage collector (libgc). There's never a need to copy anything for reasons of memory management, and indeed, ownership of memory no longer needs to be mentioned as part of APIs. You have to buy a little more RAM to get the same CPU performance, but you save hundreds of hours of programmers' time. You decide.