I've asked a couple questions (here and here) about memory management, and invariably someone suggests that I use boost::shared_ptrs.
Given how useful they seem to be, I'm seriously considering switching over my entire application to use boost::shared_ptrs.
However, before I jump in with both feet and do this, I wanted to ask -- Has anyone had any bad experiences with boost::shared_ptrs? Is there some pitfall to using them that I need to watch out for?
Right now, they seem almost too good to be true - taking care of most of my garbage collection concerns automatically. What's the downside?
The downside is they're not free. You especially shouldn't use shared_ptr/shared_array when scoped_ptr/scoped_array (or plain old stack allocation) will do. You'll need to manually break cycles with weak_ptr if you have any. The vector question you link to is one case where I might reach for a shared_ptr, the second question I would not. Not copying is a premature optimization, especially if the string class does it for you already. If the string class is reference counted, it will also be able to implement COW properly, which can't really be done with the shared_ptr<string> approach. Using shared_ptr willy-nilly will also introduce "interface friction" with external libraries/apis.
Boost shared pointers or any other technique of memory management in C++ is not a panacea. There is no substitution for careful coding. If you dive into using boost::shared_ptr be aware of object ownership and avoid circular references. You are going to need to explicitly break cycles or use boost::weak_ptr where necessary.
Also be careful to always use boost::shared_ptr for an instance from the moment it is allocated. That way you are sure you won't have dangling references. One way you can ensure that is to use factory methods that return your newly created object in a shared_ptr.
typedef boost::shared_ptr<Widget> WidgetPtr;
WidgetPtr myWidget = Widget::Create();
I use shared_ptr's often.
Since Shared_ptr's are copied by-value, you can incur the cost of copying both the pointer value and a reference count, but if boost::intrusive_ptr is used, the reference count must be added to your class, and there is no additional overhead above that of using a raw pointer.
However, in my experience, more than 99% of the time, the overhead of copying boost::shared_ptr instances throughout your code is insignificant. Usually, as C. A. R. Hoare noted, premature optimization is pointless - most of the time other code will use significantly more time than the time to copy small objects. Your mileage may vary. If profiling show the copying is an issue, you can switch to intrusive pointers.
As already noted above, cycles must be broken by using a weak_ptr, or there will be a memory leak. This will happen with data structures such as some graphs, but if, for example, you are making a tree structure where the leaves never point backwards, you can just use shared_pointers for nodes of the tree without any issues.
Using shared_ptr's properly greatly simplifies code, makes it easier to read, and easier to maintain. In many cases using them is the right choice.
Of course, as already mentioned, in some cases, using scoped_ptr (or scoped_array) is the right choice. If the pointee isn't being shared, don't use shared pointers!
Finally, the most recent C++ standard provides the std::tr1::shared_ptr template, which is now on most platforms, although I don't think there is an intrusive pointer type for tr1 (or rather, there might be, but I have not heard of it myself).
Dynamic memory overhead (i.e., extra allocations) plus all the overhead associated with reference counted smart pointers.
Related
Short Version:
Is there any acceptable reason for using non-smart pointers in modern C++?
Long Version:
we have a huge product that contains lot's of old C++ code and now we are trying to refactor it to the modern C++ era. Along with all the old fashioned code, there is huge amount of pointers passing around (mostly with SAL annotations to provide some sense of security) and I was wondering if we should change all of them to smart pointers or maybe leave some of them as is?
Trying to convert some of these codes, I ended up with a code that is simply arguable for over using smart pointers.
So the question is: is there such a thing as over using smart pointers?
Or in other words: is there any acceptable scenario for non-smart pointers these days?
Smart pointers (unique_ptr and shared_ptr) should be OWNING pointers (i.e., responsible for destruction of the object). The bottom line of using them is that any object created by new should be shoved into a unique_ptr ASAP, to prevent memory leaks. After that, the unique_ptr should end up being moved:
either into a shared_ptr if ownership should be shared,
or into a unique_ptr if ownership is determined by a scope (of a block, or the lifetime of an object).
releases should be rare. If your code passes non-owning pointers around, these should be:
raw pointers if they may be null, (obtained by get)
references if they may not be null, (obtained by get)
unique_ptrs by value if the aim of the call is transferring ownership. (in which case you'll need to move them)
Factory methods should return unique_ptrs by value. (because then, if you don't assign the return value of the factory method, the object is immediately de-allocated)
And check out Ali's answer regarding links to some philosophical points of handling legacy code. (Which I totally agree on)
Short Version:
Is there any acceptable reason for using non-smart
pointers in modern C++?
Short answer:
Definitely, if they only serve for observation, that is, they don't own the pointee. However, try to use references instead of pointers even in this case; use pointers only if you really need to make them optional (initialize with null_ptr then reassign later, for example).
Long Version:
we have a huge product that contains lot's of old C++ code and now we are trying to refactor it to the modern C++ era. [...]
Long answer:
As I am reading these lines this answer comes to mind:
Advice on working with legacy code
I wish I could upvote this answer more than once. I would quote: "[...] for each re-factor we have made we can justify 'this specific change will make the actual task we are doing now easier'. Rather than 'this is now cleaner for future work'."
Long story short, don't do big refactoring unless you really need to.
So the question is: is there such a thing as over using smart pointers?
In my opinion, std::shared_ptr is overused. It is very comfortable to use, and it gives you the illusion that you don't have to think about ownership issues. But that is not the whole picture. I fully agree with Sean Parent: "a shared pointer is as good as a global variable." Shared pointers can also introduce very difficult ownership issues, etc.
On the other hand, if you need to allocate something on the heap, use a unique_ptr. You can't overuse it, if you really need heap allocation. In my experience, using unique_ptr also leads to cleaner and easier to understand code, as the ownership issues become self-explanatory.
Interesting talks from Sean Parent on how to avoid / reduce the usage of pointers are:
Inheritance Is The Base Class of Evil
Value Semantics and Concepts-based Polymorphism
Hope this helps.
Yes, raw pointers still have a uses as an "optional reference". I.e. a T* is similar to a T&. Neither implies ownership, but a T* can be a nullptr.
Check out the talks here: http://channel9.msdn.com/Events/GoingNative/2013 (especially Stroustrup's talk).
The short answer is no, assuming "modern C++" is >= c++11
The long answer is that wasn't always the case and trying to restructure a large project is almost always hard. The way we think about problems is constrained by the tools we have to solve them. There are many cases when doing such refactoring when it simply makes more sense to use pointers than try to re-express basic logic to be class and smart pointer friendly. I think it's less of a case where smart pointers are over-used and more of a case when classes are under used. YMMV ;-)
Of course there are use cases for raw pointers in modern C++:
interfaces that must be compile-able as pure C (although the implementation itself may make use of those C++ features, that are not also C features, like classes, or smart-pointers)
code that is extremely low level, so low level, that even the simplest smart-pointer proves as being to heavy-weight
Of course those are rather rare cases and for by far the most use cases of pointers smart pointers should be just fine for new code, BUT:
If the existing code works fine with raw pointers, why invest time to rewrite it and risk to add bugs when converting it to a smart-pointer using version?
Don't refactor code, that is working fine, just because the new code better follows modern programming-standards. These programming standards are not existing for their own sake, but to make working with some code easier, so don't do refactoring, which will cost you more time than they can save you in the future.
That means: If it will cost you more time to check, which of those pointers can be safely converted into smart-pointers and which can't and to hunt the bugs, that your refactoring may have introduced, than you will be able to save on future maintenance work due to the refactoring, then simply don't refactor and let it stay as it is.
If the refactoring will save more time than it costs for only some parts of the code base, then consider to only refactor those parts of the code base.
More and more I hear, that I should use smart pointers instead of naked pointers, despite I have effective memory leak system implemented.
What is the correct programming approach on using smart pointers please? Should they really be used, even if I check memory leaks on allocated memory blocks? Is it still up to me? If I do not use them, can this be considered as programming weakness?
If the smart pointers(ex: std::auto_ptr) are strongly recommended, should I use them instead of every naked pointer?
You should use RAII to handle all resource allocations.
Smart pointers are just one common special case of that rule.
And smart pointers are more than just shared_ptr. There are different smart pointers with different ownership semantics. Use the one that suits your needs. (The main ones are scoped_ptr, shared_ptr, weak_ptr and auto_ptr/unique_ptr (prefer the latter where available). Depending on your compiler, they may be available in the standard library, as part of TR1, or not at all, in which case you can get them through the Boost libraries.
And yes, you should absolutely use these. It costs you nothing (if done correctly, you lose zero performance), and it gains you a lot (memory and other resources are automatically freed, and you don't have to remember to handle it manually, and your code using the resource gets shorter and more concise)
Note that not every pointer usage represents some kind of resource ownership, and so not all raw pointer usage is wrong. If you simply need to point to an object owned by someone else, a raw pointer is perfectly suitable. But if you own the object, then you should take proper ownership of it, either by giving the class itself RAII semantics, or by wrapping it in a smart pointer.
You can't just blindly substitute std::auto_ptr for every raw pointer. In particular, auto_ptr transfers ownership on assignment, which is great for some purposes but definitely not for others.
There is a real reason there are several varieties of smart pointers (e.g., shared_ptr, weak_ptr, auto_ptr/unique_ptr, etc.) Each fulfills a different purpose. One major weakness of a "raw" pointer is that it has so many different uses (and has that versatility largely because it does little or nothing to assist in any one purpose). Smart pointers tend to be more specialized, which means they can be more intelligent about doing one thing well, but also means you have to pick the right one for the job or it'll end up dong the wrong things entirely.
Smart pointers allows to define automatically the life-time of objects it refers to. That's the main thing to understand.
So, no, you shouldn't use smart pointers everywhere, only when you want to automate life-time of your objects instead of having, for example, an object managing those objects inside from birth to death. It's like any tool : it solves specific kind of problems, not all problems.
For each object, you should think about the life cycle it will go through, then choose one of the simplest correct and efficient solution. Sometimes it will be shared_ptr because you want the object to be used by several components and to be automatically destroyed once not used anymore. Sometimes you need the object only in the current scope/parent-object, so scoped_ptr might be more appropriate. Sometimes you need only one owner of the instance, so unique_ptr is appropriate. Maybe you'll find cases where you know an algorithm that might define/automate the lifetime of an object, so you'll write your own smart pointer for it.
For example of opposite case, using pools forbids you to use smart_ptr. Naked pointers might be a more welcome simple and efficient solution in this particular (but common in embedded software) case.
See this answer (from me) for more explainations : https://softwareengineering.stackexchange.com/questions/57581/in-c-is-it-a-reflection-of-poor-software-design-if-objects-are-deleted-manuall/57611#57611
Should they really be used, even if I check memory leaks on allocated memory blocks?
YES
The whole purpose of smart pointers is, it help you implement RAII(SBRM), which basically lets the resource itself take the responsibility of its deallocation and the resource doesn't have to rely on you explicitly remembering to deallocate it.
If I do not use them, can this be considered as programming weakness?
NO,
It is not a weakness but a inconvenience or unnecessary hassle to explicitly manage the resources by yourself if you are not using Smart pointers(RAII). The purpose of smart pointers to implement RAII is to provide efficient and hassle free way of handling resources and you would just not be making use of it if you are not using it. It is highly recommended to use it purely for the numerous advantages it provides.
If the smart pointers(ex: std::auto_ptr)are strongly recommended, should I use them instead of every naked pointer?
YES
You should use smart pointers wherever possible because simply there is no drawback of using them and just numerous advantages to use them.
Don't use auto_ptr though because it is already deprecated!! There are various other smart pointers available that you can use depending on the requirement. You can refer the link above to know more about them.
It's a tricky question, and the fact that there is currently a mode to
use smart pointers everywhere doesn't make things any easier. Smart
pointers can help in certain situations, but you certainly can't just
use them everywhere, without thinking. There are many different types
of smart pointers, and you have to think about which one is appropriate
in every case; and even then, most of your pointers (at least in typical
applications in the domains I've worked in) should be raw pointers.
Regardless of the approach, several points are worth mentionning:
Don't use dynamic allocation unless you have to. In many
applications, the only things that need to be allocated dynamically
are objects with specific lifetimes, determined by the application
logic. Don't use dynamic allocation for objects with value semantics.
With regards to entity object, those which model something in the
application domain: these should be created and destructed according
to the program logic. Irregardless of whether there are pointers to
them or not. If their destruction causes a problem, then you have an
error in your program logic somewhere (not handling an event correctly,
etc.), and using smart pointers won't change anything.
A typical example of an entity object might be client connection in a
server, is created when the client connects, and destructed when the
client disconnects. In many such cases, the most appropriate management
will be a delete this, since it is the connection which will receive
the disconnection event. (Objects which hold pointers to such an object
will have to register with it, in order to be informed of its
destruction. But such pointers are purely for navigation, and shouldn't
be smart pointers.)
What you'll usually find when people try to use smart pointers
everywhere is that memory leaks; typical reference counters don't
handle cycles, and of course, typical applications are full of cycles: a
Connection will point to the Client which is connected to it, and
the Client will contain a list of Connection where it is connected.
And if the smart pointer is boost::shared_ptr, there's also a definite
risk of dangling pointers: it's far to easy to create two
boost::shared_ptr to the same address (which results in two counters
for the references).
If the smart pointers(ex: std::auto_ptr) are strongly recommended, should I use them instead of every naked pointer?
In my opinion, yes, you should it for every pointer that you own.
Here are my ideas on resource management in C++ (feel free to disagree):
Good resource management requires thinking in terms of ownership.
Resources should be managed managed by objects (RAII).
Usually single ownership is preferred over shared ownership.
Ideally the creator is also the owner of the object. (However, there are situations where ownership transfer is in order.)
This leads to the following practices:
Make boost::scoped_ptr the default choice for local and member variables. Do keep in mind that using scoped_ptr for member variables will make your class non-copyable. If you don't want this see next point.
Use boost::shared_ptr for containers or to enable shared ownership:
// Container of MyClass* pointers:
typedef boost::shared_ptr<MyClass> MyClassPtr;
std::vector<MyClassPtr> vec;
The std::auto_ptr (C++03) can be used for ownership transfer. For example as the return value of factory or clone methods:
// Factory method returns auto_ptr
std::auto_ptr<Button> button = Button::Create(...);
// Clone method returns auto_ptr
std::auto_ptr<MyClass> copy = obj->clone();
// Use release() to transfer the ownership to a scoped_ptr or shared_ptr
boost::scoped_ptr<MyClass> copy(obj->clone().release());
If you need to store a pointer that you don't own then you can use a raw pointer:
this->parent = inParentObject;
In certain situations a boost::weak_pointer is required. See the documentation for more information.
In general you should prefer smart pointers, but there are a couple of exceptions.
If you need to recast a pointer, for example to provide a const version, that becomes nearly impossible with smart pointers.
Smart pointers are used to control object lifetime. Often when you are passing a pointer to a function, the function will not affect the lifetime; the function does not try to delete the object, and it does not store a copy of the pointer. The calling code cannot delete the object until the function returns. In that case a dumb pointer is perfectly acceptable.
Yes. Assuming you have C++0x available to you, use unique_ptr or shared_ptr (as appropriate) to wrap all the raw pointers you new up. With the help of make_shared, shared_ptr is highly performant. If you don't need reference counting then unique_ptr will get you better perf. Both of them behave properly in collections and other circumstances where auto_ptr was a dumb pointer.
Using smart pointers (shared_ptr or otherwise) EVERYWHERE is a bad idea. It's good to use shared_ptr to manage the lifetime of objects/resources but it's not a good idea to pass them as parameters to functions etc. That increases the likelihood of circular references and other extremely hard to track bugs (Personal experience: Try figuring out who should not be holding onto a resource in 2 millions lines of code if every function invocation changes the reference count - you will end up thinking the guys who do this kind of thing are m***ns). Better to pass a raw pointer or a reference.
The situation is even worse when combined with lazy instantiation.
I would suggest that developers should know the lifecycle of the objects they write and use shared_ptr to control that (RAII) but not extend shared_ptr use beyond that.
there are already a couple of questions regarding this topic, but I am still not sure what to do: Our codebase uses shared_ptr at many places. I have to admit that we did not define ownership clearly when writing it.
We have some methods like
void doSomething(shared_ptr<MyClass> ptr)
{
//doSomething() is a member function of a class, but usually won't store the ptr
ptr->foo();
...
}
After having discovered the first (indirect) circular dependencies I would like to correct the mistakes in our design. But I'm not exactly sure how. Is there any benefit in changing the method from above to
void doSomething(weak_ptr<MyClass> ptr)
{
shared_ptr<MyClass> ptrShared = ptr.lock();
ptrShared->foo();
...
}
?
I am also confused because some people say (including the Google Style guide) that in the first place it's important to get ownership correct (which would probably mean introduction of many weak_ptrs, e.g. in the example with the methods above, but also for many member variables that we have). Others say (see links below) that you should use weak_ptr to break cyclic dependencies. However, detecting them is not always easy, so I wonder if I really should use shared_ptr until I run into problems (and realize them), and then fix them??
Thanks for your thoughts!
See also
shared_ptr and weak_ptr differences
boost::shared_ptr cycle break with weak_ptr
boost, shared ptr Vs weak ptr? Which to use when?
We did not define ownership clearly.
You need to clearly define who owns what. There's no other way to solve this. Arbitrarily swapping out some uses of shared_ptr with weak_ptr won't make things better.
There is no benefit in changing your design above from shared_ptr to weak_ptr. Getting ownership right is not about using weak_ptrs, it's about managing who stores the shared_ptr for any significant length of time. If I pass a shared_ptr to a method, assuming I don't store that shared_ptr into a field in my object as part of that method, I haven't changed who owns that data.
In my experience the only reason for using weak_ptr is when you absolutely must have a cycle of pointers and you need to break that cycle. But first you should consider if you can modify your design to eliminate the cycle.
I usually discourage mixing shared_ptr's and raw pointers. It inevitably happens (though it probably shouldn't) that a raw pointer needs to be passed to a function that takes a shared_ptr of that type. A weak_ptr can be safely converted to a shared_ptr, with a raw pointer you're out of luck. Even worse, a developer inexperienced with shared_ptr's may create a new shared_ptr from that raw pointer and pass it to the function, causing that pointer to be deleted when the function returns. (I actually had to fix this bug in production code, so yes it does happen :) )
It sounds like you have a design problem. shared_ptr provides
a simple to use implementation for specific design solutions,
but it (nor anything else) can replace the design. Until you
have determined what the actual lifetime of each type of object
should be, you shouldn't be using shared_ptr. Once you've done
that, most of the shared_ptr/weak_ptr issues should disappear.
If, having done that, and determined that the lifetime of some
objects does depend on that of other objects, and there are
cycles in this dependency, you have to determine (at the design
level, again) how to manage those cycles---it's quite possible,
for example, that in those cases, shared_ptr isn't the correct
solution, or that many of the pointers involved are just for
navigation, and should be raw pointers.
At any rate, the answer to your question resides at the design
level. If you have to ask it when coding, then it's time to go
back to design.
Some people are right: you should at first have very clear picture about objects' ownership in your project.
shared_ptrs are shared, i.e. "owned by community". That might or might not be desirable. So I would advise to define ownership model and then to not abuse shared_ptr semantics and use plain pointers whenever ownership should not be "shared" more.
Using weak_ptrs would mask the problem further rather than fix it.
I have a piece of performance critical code. The class and objects are fairly large, hence, it would be stored as pointers in the STL container. Problems arise when the pointers to objects need to be stored in multiple different containers based on some logic. It is very messy in handling the ownership of the object as I couldn't isolate the ownership of the object to a single containers(which I could just delete from the single container). Other than using smart pointer (since it is performance critical and smart pointer might affects the performance), what could I do?
Thanks.
You are asking for impossible - from one point, you are asking for exceptional performance, such that smart pointers you claim cannot provide, and you also happen to ask for safety and tidiness. Well, one comes at the cost of another, actually. You could, of course try to write your own shared pointer, which would be more lightweight than boost's, but still provide the basic functionality. Incidentally, have you actually tried boost::shared_ptr? Did it actually slow down the performance?
Your question is very awkward: you ask for performance with a messy logic ?
shared_ptr have incredible performance, really, and though you can get better it is probably your best choice: it works.
You could look up another Boost smart pointer though: boost::intrusive_ptr.
This is done at the cost of foregoing: weak_ptr and in exchange allows to have a single memory allocation for both the counter and the object. Packing up the two yields a SMALL increase in performance.
If you do not have cyclic reference, try and check it out, it might be what you were looking for.
Intrusive smart pointers are typically more efficient than normal smart pointers, yet easier than dumb pointers. For instance, check out boost::intrusive_ptr<T>
If the objects don't refer to one another, manual reference counting might be worth trying. There would be more cost when adding to or removing from a list, but no overhead to the actual object access. (This can be painful to diagnose when you get it wrong, so I recommend being careful to get it right.)
If there is dead time between operations, consider a sort of garbage collect. Maintain the list of all objects (an intrusive list would probably do). When you have time to spare, cross-reference this against the other lists; any objects that aren't in a list can get deleted. You don't need an extra array to do this (just a global counter and a last-seen counter on each object) so it could be reasonably efficient.
Another option would be to use a smart pointer that provides access to the underlying pointer. If you're trying to avoid the overhead of calling an overloaded operator-> a lot then this might be worth trying. Store the smart pointers in the lists (this does the lifetime management for you) and then when running through the objects you can retrieve the raw pointer for each and operate using that (so you don't incur the overhead of any overloaded operator-> etc.). For example:
std::vector<smart_ptr<T> > objects;
if(!objects.empty()) {
smart_ptr<T> *objects_raw=&objects[0];
for(size_t n=objects.size(),i=0;i<n;++i) {
T *object=objects_raw[i].get_ptr();
// do stuff
}
}
This is the sort of approach I prefer personally. Long-term storage gets a smart pointer, short-term storage gets a plain pointer. The object lifetimes are easy to manage, and you don't fall foul of 1,000,000 tiny overheads (more important for keeping the debug build runnable than it is for the release build, but it can easily add to wasted time nonetheless).
I came to know that smart pointer is used for resource management and supports RAII.
But what are the corner cases in which smart pointer doesn't seem smart and things to be kept in mind while using it ?
Smart pointers don't help against loops in graph-like structures.
For example, object A holds a smart pointer to object B and object B - back to object A. If you release all pointers to both A and B before disconnection A from B (or B from A) both A and B will hold each other and form a happy memory leak.
Garbage collection could help against that - it could see that both object are unreachable and free them.
I would like to mention performance limitations. Smart pointers usually use atomic operations (such as InterlockedIncrement in Win32 API) for reference counting. These functions are significantly slower than plain integer arithmetic.
In most cases, this performance penalty is not a problem, just make sure you don't make too many unnecessary copies of the smart pointer object (prefer to pass the smart pointer by reference in function calls).
This is quite interesting: Smart Pointers.
It's a sample chapter from "Modern C++ Design" by Andrei Alexandrescu.
Watch out at the transitions - when assigning between raw and smart pointers. Bad smart pointers - like _com_ptr_t - make it worse by allowing implicit conversions. Most errors happen at the transition.
Watch out for cycles - as mentioned, you need weak pointers to break the cycles. However, in a complex graph that's not always easy to do.
Too much choice - most libraries offer different implementations with different advantages / drawbacks. Unfortunately, most of the time these different variants are not compatible, which becomes a probem when mixing libraries. (say, LibA uses LOKI, LibB uses boost). Having to plan ahead for enable_shared_from_this sucks, having to decide naming conventions between intrusive_ptr, shared_ptr and weak_ptr for a bunch of objects sucks.
For me, the single most e advantage of shared_ptr (or one of similar functionality) is that it is coupled to its destruction policy at creation. Both C++ and Win32 offers so many ways of getting rid of things it's not even funny. Coupling at construction time (without affecting the actual type of the pointer) means I have both policies in one place.
Beside technical limitations (already mentioned : circular dependencies), i'd say that the most important thing about smart pointers is to remember that it's still a workaround to get heap-allocated-objects deleted.
Stack allocation is the best option for most cases - along with the use of references - to manage the lifetime of objects.
The following article is a very interesting paper
Smart Pointers: Can't Live With 'Em, Can't Live Without 'Em
Here are a few things
There's no definite entity which destroys the object. Often it is desired to know exactly when and how an object is being destroyed
Circular dependencies - If they exist you'll have a memory leak. That's usually where weak_ptr come to the rescue.
There is a problem with reference counting in certain types of data structures that have cycles. There can also be problems with accessing smart pointers from multiple threads, concurrent access to reference counts can cause problems. There's a utility in boost called atomic.hpp that can mitigate this problem.
Many people run into problems when using smart pointers mixed with raw pointers (to the same objects). A typical example is when interacting with an API that uses raw pointers.
For example; in boost::shared_ptr there is a .get() function that returns the raw pointer. Good functionality if used with care, but many people seem to trip on it.
IMHO it's an example of a "leaky abstraction".
Raymond Chen is notoriously ambivalent about smart pointers. There are issues about when the destructor actually runs (please note, the destructor runs at a well-defined time in a well-defined order; it's just that once in a while you'll forget that it's after the last line in your function).
Also remember that "smart pointer" is a pretty big category. I include std::vector in that category (a std::vector is essentially a smart array).