开发者

Usage of Smart Pointers as a Programming Standard?

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) ar开发者_如何学Ce 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):

  1. Good resource management requires thinking in terms of ownership.
  2. Resources should be managed managed by objects (RAII).
  3. Usually single ownership is preferred over shared ownership.
  4. 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:

  1. 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.

  2. 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;

  3. 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());

  4. If you need to store a pointer that you don't own then you can use a raw pointer:

    this->parent = inParentObject;

  5. 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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜