When to use shared_ptr and when to use raw pointers?
Your analysis is quite correct, I think. In this situation, I also would return a bare B*
, or even a [const] B&
if the object is guaranteed to never be null.
Having had some time to peruse smart pointers, I arrived at some guidelines which tell me what to do in many cases:
- If you return an object whose lifetime is to be managed by the caller, return
std::unique_ptr
. The caller can assign it to astd::shared_ptr
if it wants. - Returning
std::shared_ptr
is actually quite rare, and when it makes sense, it is generally obvious: you indicate to the caller that it will prolong the lifetime of the pointed-to object beyond the lifetime of the object which was originally maintaining the resource. Returning shared pointers from factories is no exception: you must do this eg. when you usestd::enable_shared_from_this
. - You very rarely need
std::weak_ptr
, except when you want to make sense of thelock
method. This has some uses, but they are rare. In your example, if the lifetime of theA
object was not deterministic from the caller's point of view, this would have been something to consider. - If you return a reference to an existing object whose lifetime the caller cannot control, then return a bare pointer or a reference. By doing so, you tell the caller that an object exists and that she doesn't have to take care of its lifetime. You should return a reference if you don't make use of the
nullptr
value.
Whether to pass shared pointer or raw pointer to a function
I would suggest the following approach to looking at code something like this:
There are some other options like weak_ptr
, but for this it is probably not worth looking at.
So for your example, we can see that ThirdParty_DoStuff
does not take ownership, so we won't either, so you can choose between a reference and a pointer depending on if the argument is mandatory or not respectively.
When should I use raw pointers over smart pointers?
No, it's not true. If a function needs a pointer and has nothing to do with ownership, then I strongly believe that a regular pointer should be passed for the following reasons:
- No ownership, therefore you don't know what kind of a smart pointer to pass
- If you pass a specific pointer, like
shared_ptr
, then you won't be able to pass, say,scoped_ptr
The rule would be this - if you know that an entity must take a certain kind of ownership of the object, always use smart pointers - the one that gives you the kind of ownership you need. If there is no notion of ownership, never use smart pointers.
Example1:
void PrintObject(shared_ptr<const Object> po) //bad
{
if(po)
po->Print();
else
log_error();
}
void PrintObject(const Object* po) //good
{
if(po)
po->Print();
else
log_error();
}
Example2:
Object* createObject() //bad
{
return new Object;
}
some_smart_ptr<Object> createObject() //good
{
return some_smart_ptr<Object>(new Object);
}
What is a smart pointer and when should I use one?
UPDATE
This answer is rather old, and so describes what was 'good' at the time, which was smart pointers provided by the Boost library. Since C++11, the standard library has provided sufficient smart pointers types, and so you should favour the use of std::unique_ptr
, std::shared_ptr
and std::weak_ptr
.
There was also std::auto_ptr
. It was very much like a scoped pointer, except that it also had the "special" dangerous ability to be copied — which also unexpectedly transfers ownership.
It was deprecated in C++11 and removed in C++17, so you shouldn't use it.
std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership.
// p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.
OLD ANSWER
A smart pointer is a class that wraps a 'raw' (or 'bare') C++ pointer, to manage the lifetime of the object being pointed to. There is no single smart pointer type, but all of them try to abstract a raw pointer in a practical way.
Smart pointers should be preferred over raw pointers. If you feel you need to use pointers (first consider if you really do), you would normally want to use a smart pointer as this can alleviate many of the problems with raw pointers, mainly forgetting to delete the object and leaking memory.
With raw pointers, the programmer has to explicitly destroy the object when it is no longer useful.
// Need to create the object to achieve some goal
MyObject* ptr = new MyObject();
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?
A smart pointer by comparison defines a policy as to when the object is destroyed. You still have to create the object, but you no longer have to worry about destroying it.
SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.
// Destruction of the object happens, depending
// on the policy the smart pointer class uses.
// Destruction would happen even if DoSomething()
// raises an exception
The simplest policy in use involves the scope of the smart pointer wrapper object, such as implemented by boost::scoped_ptr
or std::unique_ptr
.
void f()
{
{
std::unique_ptr<MyObject> ptr(new MyObject());
ptr->DoSomethingUseful();
} // ptr goes out of scope --
// the MyObject is automatically destroyed.
// ptr->Oops(); // Compile error: "ptr" not defined
// since it is no longer in scope.
}
Note that std::unique_ptr
instances cannot be copied. This prevents the pointer from being deleted multiple times (incorrectly). You can, however, pass references to it around to other functions you call.
std::unique_ptr
s are useful when you want to tie the lifetime of the object to a particular block of code, or if you embedded it as member data inside another object, the lifetime of that other object. The object exists until the containing block of code is exited, or until the containing object is itself destroyed.
A more complex smart pointer policy involves reference counting the pointer. This does allow the pointer to be copied. When the last "reference" to the object is destroyed, the object is deleted. This policy is implemented by boost::shared_ptr
and std::shared_ptr
.
void f()
{
typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
MyObjectPtr p1; // Empty
{
MyObjectPtr p2(new MyObject());
// There is now one "reference" to the created object
p1 = p2; // Copy the pointer.
// There are now two references to the object.
} // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero.
// The object is deleted.
Reference counted pointers are very useful when the lifetime of your object is much more complicated, and is not tied directly to a particular section of code or to another object.
There is one drawback to reference counted pointers — the possibility of creating a dangling reference:
// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!
Another possibility is creating circular references:
struct Owner {
std::shared_ptr<Owner> other;
};
std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1
// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!
To work around this problem, both Boost and C++11 have defined a weak_ptr
to define a weak (uncounted) reference to a shared_ptr
.
New to c++11 features, proper use of shared_ptr?
...it's useful when many instances may be sharing the same object. Correct?
Not exactly. It is useful when many instances may be owning the same object. Sharing is not enough to justify using a std::shared_ptr
as there is certainly some overhead to using it.
When you create dynamic resources you need to think about ownership ie. who is responsible for deleting it? The object that should be responsible for deleting the resource should manage the resource using some kind of smart pointer (or a container).
If only one object is responsible for deciding when the resource must be deleted then use a std::unique_ptr
. If other objects/functions need to share access to the resource but will never be responsible for deleting it, then pass them a reference or a raw pointer to the resource.
The time to use a std::shared_ptr
is when you can not know which of the objects that are sharing the resource will be the one that needs to delete it. In that case each object should hold ownership of the resource by holding a std::shared_ptr
.
And even when several objects share ownership through a std::shared_ptr
they should still only pass a reference or a raw pointer to objects/functions that do not need ownership rights.
Another problem with passing std::stared_ptr
round willy-nilly (where they are not needed) is that they can suffer from the Java memory leak problem. That is when objects never die because some reference to them remains in a forgotten part of the software. They can gradually accumulate and eat away your memory.
Typically you should prefer keeping your resources in a container like a std::vector
or a std::map
:
std::map<int, Tile> Tiledb;
The container manages the destruction of the Tile
so no need for a smart pointer.
If, however, you were using polymorphic Tile
objects then you would need to store them using a pointer. For this prefer to use std::unique_ptr
:
// When the Tiles are no longer needed after the map is destroyed
std::map<int, std::unique_ptr<Tile>> Tiledb;
If other objects need to keep accessing the Tile
objects after the map is destroyed then a std::shared_ptr
may be appropriate:
// only when Tiles need to keep living after the map is destroyed.
std::map<int, std::shared_ptr<Tile>> Tiledb;
Should I delete pointer from `new` passed to a function which makes into a `shared_ptr`?
The very idea of a constructor taking a raw pointer is to pass the ownership to std::shared_ptr
. So, no, you don't have to delete
a raw pointer passed to std::shared_ptr
. Doing this will lead to a double deletions, which is UB.
Note that in general passing a raw pointer is dangerous. Consider the following more generalized example:
void addFoo(Foo *foo){
// some code which could throw an exception
auto my_foo = std::shared_ptr<Foo>(foo);
}
If an exception is throw before my_foo
is constructed, foo
will leak.
If you have no special reason to pass a raw pointer, consider the following alternative:
class Bar {
public:
template<class... Args>
void addFoo(Args... args){
auto my_foo = std::make_shared<Foo>(args...);
}
};
int main() {
auto bar = Bar();
bar.addFoo();
return 0;
}
Here you pass arguments (if you have any) to construct Foo
inside addFoo()
instead of constructing Foo
before invoking addFoo()
.
Perfect forwarding of args...
could be used if it is needed:
template<class... Args>
void addFoo(Args&&... args){
auto my_foo = std::make_shared<Foo>(std::forward<Args>(args)...);
}
Related Topics
How to Building Static Qt with Static Openssl
How to Use Nested Loops with Vectors in Cpp
Why Using the Const Keyword Before and After Method or Function Name
Converting a Variable Name to a String in C++
How to Define a String Literal in Gcc Command Line
C++ Ifstream Failbit and Badbit
Refreshing the Auto Complete (Intellisense) Database in Visual Studio
Checking Value Exist in a Std::Map - C++
Visual Studio: Run C++ Project Post-Build Event Even If Project Is Up-To-Date
Variadic Deduction Guide Not Taken by G++, Taken by Clang++ - Who Is Correct
C++ Sizeof(Array) Return Twice the Array's Declared Length
Why Do We Require Requires Requires
Why Can a T* Be Passed in Register, But a Unique_Ptr<T> Cannot
When Should Your Destructor Be Virtual
Why Use Precompiled Headers (C/C++)