I'd like to optimize my code. I have one class that has a shared_ptr data member. In some methods of this class, I create objects that need to use this member (just to get information from the object pointed by shared_ptr). I know that lifetime of these created objects is lower than in my main class. How to pass this pointer? I think another shared_ptrs is unnecessary (because I have a warranty that the object will exist). So what should get my created classes? Should they get raw pointer? Weak_ptr? Or the best solution is getting shared_ptr (and incrementing its reference counter)? What is the most standard solution?
2 Answers
In this case when you know the life-time of your shared resource will outlive those that you pass the pointer to the correct thing to do is pass a reference or a raw pointer:
void func(object* o)
{
// do stuff with o
}
// ...
std::shared_ptr<object> sp;
// ...
func(sp.get()); // pass raw pointer
The main reason for this is that the function can be useful no matter what kind of smart pointer is managing the resource. By accepting the raw pointer your function is able to accept objects from shared pointers as well as unique pointers and any other third party smart pointer.
There is no benefit to passing in the smart pointer unless the function needs to modify the smart pointer itself.
A good set of guidelines being produced by Bjarne Straustrup & Herb Sutter can be found here: CppCoreGuidelines
The rule about passing raw pointers (or references): F.7
Passing a smart pointer transfers or shares ownership and should only be used when ownership semantics are intended. A function that does not manipulate lifetime should take raw pointers or references instead.
Passing by smart pointer restricts the use of a function to callers that use smart pointers. A function that needs a widget should be able to accept any widget object, not just ones whose lifetimes are managed by a particular kind of smart pointer.
When passing the shared_ptr into a function that will not store the resource, pass it by reference:
void foo(const shared_ptr<T>& ptr)
{
// Basically just a pointer dereference
std::cout << ptr->bar() << '\n';
}
int main()
{
std::shared_ptr<T> ptr{std::make_shared<T>()};
foo(ptr);
}
That won't increment the reference count, but that's fine — you're effectively treating it as a raw pointer (because you're just temporarily inspecting the pointee) but in a way that's safe because if you accidentally copy it then you'll get the reference count increment that can save your life. :)
However, if foo needs to store any sort of handle to this object, then you should pass in the shared_ptr by copy … or consider using weak_ptr so that you at least get some semblance of safety.
The above contrived example is so simple that I'd actually make it the following:
void foo(const T& ptr)
{
std::cout << ptr.bar() << '\n';
}
int main()
{
std::shared_ptr<T> ptr{std::make_shared<T>()};
foo(*ptr.get());
}