auto_ptr,scoped_ptr,shared_ptr,weak_ptr
The use of auto_ptr is very simple. You have ownership of a dynamically allocated object through the constructor, and then it can be used as an object pointer. When the auto_ptr object is destroyed, it will also automatically destroy the object it owns. release can be used to manually give up ownership, and reset can be used to manually destroy internal objects.
But in fact, auto_ptr is a class that is quite easy to be misused and is often misused in practice. The reason is due to its object ownership nature and its non-trivial copy behavior.
The object ownership of auto_ptr is exclusive! This determines that it is impossible for two auto_ptr objects to have ownership of the same dynamic object at the same time, which also leads to the non-equivalent copy behavior of auto_ptr, which is accompanied by the transfer of object ownership.
At the same time, do not put auto_ptr into the container of the standard library, otherwise the unprepared copy behavior of the standard library container (the copy behavior required by the standard library container is equivalent) will lead to errors that are difficult to detect.
The special copy behavior of auto_ptr makes it a very dangerous behavior to use it to transfer dynamic objects over long distances. During the transfer process, if you are not careful, you will leave some files that are actually empty but the program itself lacks this. Cognitive auto_ptr object.
To put it simply, auto_ptr is suitable for managing dynamic objects with a short life cycle or that will not be transferred over long distances. Use auto_ptr to manage dynamically allocated objects. It is best to limit it to a certain function or a certain class. internal. In other words, the entire process of generating, using and destroying dynamic objects is within a small controlled scope, without adding some extensions to adapt to future tenses.
Several notes on auto_ptr:
1. auto_ptr cannot share ownership
2. auto_ptr cannot point to an array
3. auto_ptr cannot be used as a member of the container
4. Auto_ptr cannot be initialized through copy operation
std::auto_ptr p(new int(42)); //OK
std::atuo_ptrp = new int(42);//Error
This is because the constructor of auto_ptr is defined as explicit
5. Do not put auto_ptr into the container
shared_ptr
An important purpose of shared_ptr is to provide a standard shared ownership smart pointer.
Shared_ptr is to solve the limitations of auto_ptr in object ownership (auto_ptr is exclusive), and provides smart pointers that can share ownership using a reference counting mechanism. Of course, this will not come without any additional costs…
First of all, in addition to a pointer to the owned object (px), a shared_ptr object must also include a pointer (pn) to the reference counting proxy object (shared_count). This reference counting proxy object includes a pointer (_pi) of a real polymorphic reference counting object (sp_counted_base). The real reference counting object includes a virtual table, a virtual table pointer, and two counter.
Suppose we have multiple (5 or more) shared_ptr sharing a dynamic object, then the overhead of each shared_ptr is about 3 or 4 times that of using only native pointers (this is still an ideal situation, ignoring dynamic allocation The remaining expenses brought by the figurines). If there is only one shared_ptr exclusive dynamic object, the space overhead will be ten times higher! The overhead of auto_ptr is only twice that of using native pointers.
The time overhead is mainly in initialization and copy operations. The overhead of * and -> operator overloading is the same as auto_ptr.
Of course the overhead is not a reason not to use shared_ptr. Never perform premature optimization until the performance analyzer tells you this. This is wise advice from Hurb. The above description is just to let you understand that powerful functions are always accompanied by more overhead. Shared_ptr should be used, but it should not be abused too much, especially in some places where auto_ptr is better at it.
Most member functions are similar to auto_ptr, but without release (see comments), reset is used to give up the ownership of the owned object or change the owned object, which will cause the reference count of the original object to be reduced.
shared_ptr can be copied and assigned, the copy behavior is also equivalent, and can be compared, which means that it can be put into the general container (vector, list) and associative container (map) of the standard library.
weak_ptr
Weak_ptr is a smart pointer introduced to cooperate with shared_ptr to assist shared_ptr work. It can be constructed from a shared_ptr or another weak_ptr object. Its construction and destruction will not cause reference marks. increase or decrease in number. There is no overload * and -> but you can use lock to obtain a usable shared_ptr object
An important use of weak_ptr is to obtain the shared_ptr of this pointer through lock, so that the object itself can produce shared_ptr to manage itself, but the helper class enable_shared_from_this shared_from_this will return the shared_ptr of this, just let the class that wants to be managed by shared_ptr inherit from it
Circular reference
Reference counting is a convenient memory management mechanism, but it has a big shortcoming, that is Cannot manage circularly referenced objects.
Use boost::weak_ptr to break reference cycles
Since weak references do not change the reference count, they are similar to ordinary references.��, as long as one side of the circular reference uses a weak reference, the circular reference can be released.
Since smart pointers store the value of the pointer rather than the value of the pointer they point to, a common problem with using smart pointers in standard library containers is how to use smart pointers in algorithms; algorithms usually Need to access the values of the actual objects, not their addresses. For example, how do you call std::sort and get it sorted correctly? In fact, this problem is almost the same as saving and manipulating ordinary pointers in containers, but the fact is easily ignored (probably because we always avoid saving raw pointers in containers). Of course we cannot directly compare the values of two smart pointers, but it is easy to solve. Just use a predicate that dereferences the smart pointer, so we will create a reusable predicate so that iterators to smart pointers can be used in standard library algorithms. The smart pointer we choose here is weak_ptr.
scoped_ptr
boost::scoped_ptr is used to ensure that dynamically allocated objects can be deleted correctly. scoped_ptr has similar characteristics to std::auto_ptr, but the biggest difference is that it cannot transfer ownership while auto_ptr can. In fact, scoped_ptr can never be copied or assigned! A scoped_ptr takes ownership of the resource it points to and never relinquishes this ownership. This feature of scoped_ptr improves the performance of our code, and we can choose the most appropriate smart pointer (scoped_ptr or auto_ptr) according to our needs.
To decide whether to use std::auto_ptr or boost::scoped_ptr, consider whether transferring ownership is a feature of smart pointers that you want. If not, use scoped_ptr. It is a lightweight smart pointer; using it will not make your program larger or slower. It just makes your code more secure and easier to maintain.
The usage of scoped_ptr is no different from that of an ordinary pointer; the biggest difference is that you no longer have to remember to call delete on the pointer, and copying is not allowed. Typical pointer operations (operator* and operator->) are overloaded and provide the same syntax as raw pointers. Using scoped_ptr is as fast as using raw pointers, and there is no increase in size, so they can be widely used. When using boost::scoped_ptr, include the header file “boost/scoped_ptr.hpp”. When declaring a scoped_ptr, use the type of the referent to specify the parameters of the class template. For example, the following is a scoped_ptr containing a std::string pointer:
boost::scoped_ptr p(new std::string(“Hello”));
When a scoped_ptr is destroyed, it calls delete on the pointer it owned.
scoped_ptr is different from const auto_ptr
Attentive readers may have noticed that auto_ptr can work almost like scoped_ptr, just declare auto_ptr as const:
const auto_ptr no_transfer_of_ownership( new A);
They are close, but not the same. The biggest difference is that scoped_ptr can be reset, and the referent can be deleted and replaced when needed. And for const auto_ptr this is not possible const. Another minor difference is that they have different names: although const auto_ptr means the same thing as scoped_ptr, it is more verbose and less obvious. You should use scoped_ptr when you have it in your dictionary because it makes your intent clearer. If you want a resource to be scoped, and there should be no way to relinquish ownership of it, you should use boost::scoped_ptr.