问题
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?
回答1:
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).
release
s should be rare. If your code passes non-owning pointers around, these should be:
- raw pointers if they may be
null
, (obtained byget
) - references if they may not be
null
, (obtained byget
) unique_ptr
s 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_ptr
s 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)
回答2:
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.
回答3:
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
.
回答4:
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 ;-)
回答5:
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.
来源:https://stackoverflow.com/questions/19417574/using-non-smart-pointers-in-modern-c