Is smart pointers right?

I find smart pointers a lot more convenient than source pointers. Is it always good to use smart pointers? (Please note that I am from the Java background and therefore do not really like the idea of ​​explicit memory management. Therefore, if there are serious performance problems with smart pointers, I would like to stick to them.)

Note. Although I come from the Java background, I understand well the implementation of RAII smart pointers and concepts. Thus, you can take this knowledge for granted on your part when sending a response. I use static allocation almost everywhere and use pointers only when necessary. My question is simple: Can I always use smart pointers instead of raw pointers ???

+63
c ++
Mar 16 '10 at 12:22
source share
10 answers

Given several changes, I had the impression that useful information would be useful.

1. If not

There are two situations where you should not use smart pointers.

The first is the same situation in which you should not use the C++ class. IE: DLL border if you do not offer the source code to the client. Tell a joke.

The second happens much more often: a smart manager means ownership . You can use pointers to point to existing resources without managing their life cycle, for example:

 void notowner(const std::string& name) { Class* pointer(0); if (name == "cat") pointer = getCat(); else if (name == "dog") pointer = getDog(); if (pointer) doSomething(*pointer); } 

This example is limited. But the pointer is semantically different from the link, because it can point to an invalid location (null pointer). In this case, it’s great not to use a smart pointer instead, because you do not want to control the lifetime of the object.

2. Smart managers

If you are not writing an intelligent manager class, if you use the delete keyword, you are doing something wrong.

This is a controversial point of view, but having considered so many examples of erroneous code, I no longer risk it. So, if you write new , you need a smart manager for the newly allocated memory. And you need it right now.

This does not mean that you are less than a programmer! In contrast, code reuse that has been proven to work, and not to reuse the wheel over and over, is a key skill.

Now the real difficulty begins: what a smart manager?

3. Smart pointers

There are various smart pointers from there with different characteristics.

Skip std::auto_ptr , which you usually avoid (its copy semantics are screwed in).

  • scoped_ptr : no overhead, cannot copy or move.
  • unique_ptr : cannot move overhead, cannot copy.
  • shared_ptr / weak_ptr : some overhead (reference counting) can be copied.

Usually try to use either scoped_ptr or unique_ptr . If you need several owners, try changing the design. If you can't change the design and really need more than one owner, use shared_ptr , but be careful of link loops that need to be broken using weak_ptr somewhere in the middle.

4. Smart containers

Many smart pointers are not designed to be copied, so their use with STL containers is somewhat compromised.

Instead of resorting to shared_ptr and its overhead, use smart containers from the Boost Pointer Container . They emulate the interface of classic STL containers, but retain the pointers they own.

5. Moving your own

There are situations when you can quit your own smart manager. Make sure that you do not just miss a function in the libraries that you use in advance.

Writing a smart manager with exceptions is quite difficult. Usually you cannot assume that memory is available ( new may fail) or that Copy Constructor has a no throw guarantee.

It may be acceptable to somewhat ignore the std::bad_alloc and impose that the Copy Constructor number of helpers do not fail ... after all, that boost::shared_ptr does a parameter for its deteter D template.

But I would not recommend it, especially for a beginner. This is a complex problem, and you are unlikely to notice errors right now.

6. Examples

 // For the sake of short code, avoid in real code ;) using namespace boost; // Example classes // Yes, clone returns a raw pointer... // it puts the burden on the caller as for how to wrap it // It is to obey the `Cloneable` concept as described in // the Boost Pointer Container library linked above struct Cloneable { virtual ~Cloneable() {} virtual Cloneable* clone() const = 0; }; struct Derived: Cloneable { virtual Derived* clone() const { new Derived(*this); } }; void scoped() { scoped_ptr<Cloneable> c(new Derived); } // memory freed here // illustration of the moved semantics unique_ptr<Cloneable> unique() { return unique_ptr<Cloneable>(new Derived); } void shared() { shared_ptr<Cloneable> n1(new Derived); weak_ptr<Cloneable> w = n1; { shared_ptr<Cloneable> n2 = n1; // copy n1.reset(); assert(n1.get() == 0); assert(n2.get() != 0); assert(!w.expired() && w.get() != 0); } // n2 goes out of scope, the memory is released assert(w.expired()); // no object any longer } void container() { ptr_vector<Cloneable> vec; vec.push_back(new Derived); vec.push_back(new Derived); vec.push_back( vec.front().clone() // Interesting semantic, it is dereferenced! ); } // when vec goes out of scope, it clears up everything ;) 
+63
Mar 16
source share

Smart pointers do explicit memory management, and if you don’t understand how they do it, you are in a world of problems when programming in C ++. And remember, memory is not the only resource they manage.

But in order to answer your question, you should prefer smart pointers as a first approximation to a solution, but perhaps be prepared to discard them when necessary. Pointers (or any types) or dynamic allocation should never be used when this can be avoided. For example:

 string * s1 = new string( "foo" ); // bad string s2( "bar" ); // good 

Edit: To answer your question about the add-on: “Can I always use smart pointers instead of raw pointers? Then no, you can’t. If (for example) you need to implement your own version of the new operator, you need to make it return a pointer, and not a smart pointer.

+18
Mar 16 '10 at 12:31
source share

Normally, you should not use pointers (smart or others) if you do not need them. It is better to make local variables, class members, vector elements and similar elements normal objects instead of pointers to objects. (Since you came from Java, you are probably tempted to highlight everything with new , which is not recommended.)

This approach (" RAII ") saves you from worrying about pointers most of the time.

When you need to use pointers, it depends on the situation and why you need pointers, but you can usually use smart pointers. It may not always be (bold), this is the best option, but it depends on the specific situation.

+13
Mar 16 '10 at 12:33
source share

A good time to not use smart pointers is on the edge of the DLL interface. You do not know if other executables with the same compiler / libraries will be created. Your standard DLL call does not specify what standard classes or TR1 classes look like, including smart pointers.

In an executable or library, if you want to represent ownership of pointee, then smart pointers on average are the best way to do this. So it’s good that you always want to use them in preference for raw ones. In fact, you can always use them, that's another matter.

For a specific example, when not to, suppose that you are writing a representation of a common graph, with vertices represented by objects and edges represented by pointers between objects. Ordinary smart pointers will not help you: graphics can be cyclical, and no particular node can be responsible for managing the memory of other nodes, so general and weak pointers are insufficient. For example, you can put everything in a vector and use indexes instead of pointers, or put everything in deque and use raw pointers. You can use shared_ptr if you want, but it won't add anything except overhead. Or you can search for a GC with a label.

A more marginal case: I prefer to see that the functions accept the parameter with a pointer or a link, and promise not to save a pointer or a link to it, but not to accept shared_ptr and leave to wonder if they can save the link after they return, perhaps if you change the reference again, you will break something, etc. Without preserving links, this is something that is often not explicitly documented, it just goes without saying. Perhaps this should not be, but it is. Smart pointers imply something about ownership, and falsely imply that this can be misleading. Therefore, if your function accepts shared_ptr , be sure to write down whether it can save the link or not.

+9
Mar 16 '10 at 13:53
source share

In many situations, I find that they are definitely the way to go (less dirty cleaning code, less risk of leaks, etc.). However, there are some very small additional costs. If I wrote some code that was supposed to be as fast as possible (say, a hard loop that was supposed to make some sort of allocation and free), I probably would not use a smart pointer in the hope that you increase the speed a little. But I doubt that this would make any measurable difference in most situations.

+6
Mar 16 '10 at 12:29
source share

In general, no, you cannot always use smart pointers. For example, when you use other frameworks that do not use a smart pointer (like Qt), you also need to use raw pointers.

+4
Mar 16 '10 at 13:20
source share

If you are working with a resource, you should always use RAII methods, since in the case of memory some form of smart pointer is used (note: smart, not shared_ptr ), select the smartest pointer that is most suitable for your specific use case) . This is the only way to avoid leaks with exceptions.

There are still cases where raw pointers are needed when resource management is not handled through a pointer. In particular, this is the only way to have a reset link. Consider storing a link in an object whose life time cannot be explicitly processed (attribute member, object on the stack). But this is a very specific case, which I saw only in real code. In most cases, using shared_ptr is the best approach to sharing an object.

+2
Mar 16 '10 at 12:40
source share

Yes, but I went several projects without using a smart pointer or any pointers. Good practice using containers like deque, list, map, etc. As an alternative, I use links whenever possible. Instead of passing a pointer, I pass a link or a link to a constant, and it is almost always illogical to delete / free the link, so I never have a problem (usually I create them on the stack, I write { Class class; func(class, ref2, ref3); }

+1
Mar 16 '10 at 12:37
source share

My approach to smart pointers: GREAT, when it's hard to know when a release can happen (say, inside a try / catch block or inside a function that calls a function (or even a constructor!) That can kick you out of your current function) or adding better control memory to a function that returns everywhere in the code. Or put pointers in containers.

Smart pointers have costs that you might not want to pay for your entire program. If memory management is easy to do manually ("Hmm, I know that when this function ends, I need to remove these three pointers, and I know that this function will be completed"), then why spend cycles on the computer this?

+1
Mar 16 '10 at 13:08
source share

It. The smart pointer is one of the cornerstones of the old Cocoa ecosystem (Touch). I believe that he continues to influence the new.

0
Jun 12 '17 at 23:27
source share



All Articles