A brief analysis of Boost smart pointer: scoped_ptr shared_ptr weak_ptr_c language

Source: Internet
Author: User
Tags garbage collection

I. SCOPED_PTR
Boost::scoped_ptr and Std::auto_ptr are very similar, a simple smart pointer that ensures that objects are automatically freed after they leave the scope. The following code illustrates the basic application of the pointer:

Copy Code code as follows:

#include <string>
#include <iostream>
#include <boost/scoped_ptr.hpp>

Class implementation
{
Public
~implementation () {std::cout << "destroying implementation\n";}
void Do_something () {std::cout << "did something\n";}
};

void Test ()
{
Boost::scoped_ptr<implementation> Impl (New Implementation ());
Impl->do_something ();
}

void Main ()
{
std::cout<< "Test Begin ... \ n";
Test ();
std::cout<< "Test end.\n";
}


The output of this code is:
Copy Code code as follows:

Test Begin ...
Did something
Destroying implementation
Test end.

You can see that when the implementation class is removed from its impl scope, it is automatically deleted, which avoids memory leaks because you forgot to manually call delete.

Boost::scoped_ptr Features:
The implementation of BOOST::SCOPED_PTR is very similar to Std::auto_ptr, which uses a stack object to manage objects on a heap so that objects on the heap are automatically deleted as objects on the stack are destroyed. The difference is that Boost::scoped_ptr has a more restrictive use--not a copy. This means that the Boost::scoped_ptr pointer cannot convert its ownership.

1. Cannot convert ownership
The object lifecycle managed by Boost::scoped_ptr is limited to an interval (between the "{}" of the pointer) and cannot be uploaded to the interval, meaning that the Boost::scoped_ptr object is not a return value for the function (std::auto_ PTR can).

2. Cannot share ownership
This is similar to the std::auto_ptr. This feature on the one hand makes the pointer simple and easy to use. On the other hand, it also creates a weak function--it cannot be used in STL containers.

3. Cannot be used to manage array objects
Because Boost::scoped_ptr deletes the managed object through delete, and the array objects must be removed by deletep[], Boost::scoped_ptr cannot manage the array objects, and if you want to manage the array objects you need to use boost:: Scoped_array class.

Common operations for Boost::scoped_ptr:
can be reduced to the following form:

Copy Code code as follows:

Namespace Boost {

Template<typename T> class Scoped_ptr:noncopyable {
Public
Explicit Scoped_ptr (t* p = 0);
~scoped_ptr ();

void Reset (t* p = 0);

t& operator* () const;
t* operator-> () const;
t* get () const;

void Swap (scoped_ptr& b);
};

Template<typename t>
void Swap (Scoped_ptr<t> & A, scoped_ptr<t> & B);
}


Its common operations are as follows:

member functions

Function

Operator* ()

To access the members of the managed object in the form of a reference

Operator-> ()

To access the members of the managed object as a pointer

Get ()

Frees managed objects and manages another object

Swap (scoped_ptr& b)

Swap two Boost::scoped_ptr managed objects



The following test code demonstrates the basic usage of these functional functions.
Copy Code code as follows:

#include <string>
#include <iostream>

#include <boost/scoped_ptr.hpp>
#include <boost/scoped_array.hpp>

#include <boost/config.hpp>
#include <boost/detail/lightweight_test.hpp>

void Test ()
{
Test scoped_ptr with a built-in type
LONG * LP = new Long;
Boost::scoped_ptr<long> SP (LP);
Boost_test (Sp.get () = LP);
BOOST_TEST (LP = = Sp.get ());
Boost_test (&*SP = = LP);

*SP = 1234568901L;
Boost_test (*sp = = 1234568901L);
Boost_test (*LP = = 1234568901L);

long * LP2 = new Long;
Boost::scoped_ptr<long> SP2 (LP2);

Sp.swap (SP2);
Boost_test (sp.get () = = LP2);
Boost_test (Sp2.get () = LP);

Sp.reset (NULL);
Boost_test (sp.get () = NULL);

}

void Main ()
{
Test ();
}


Selection of Boost::scoped_ptr and std::auto_ptr:
The functions and operations of BOOST::SCOPED_PTR and Std::auto_ptr are very similar, and how you choose between them depends on whether you need to transfer ownership of the managed objects (such as whether you need to return a value as a function). If this is not the case, you can use Boost::scoped_ptr to get the compiler to do a more rigorous check to find some incorrect assignment operations.

Two. shared_ptr
Although Boost::scoped_ptr is easy to use, it cannot share ownership but greatly limits its scope, and boost::shared_ptr can address this limitation. As the name suggests, Boost::shared_ptr is a smart pointer that can share ownership, and first let's look at its basic usage in one example:

Copy Code code as follows:

#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>

Class implementation
{
Public
~implementation () {std::cout << "destroying implementation\n";}
void Do_something () {std::cout << "did something\n";}
};

void Test ()
{
Boost::shared_ptr<implementation> SP1 (new implementation ());
std::cout<< "The Sample now has" <<sp1.use_count () << "references\n";

Boost::shared_ptr<implementation> SP2 = SP1;
std::cout<< "The Sample now has" <<sp2.use_count () << "references\n";

Sp1.reset ();
std::cout<< "after Reset SP1." The Sample now has "<<sp2.use_count () <<" references\n ";

Sp2.reset ();
std::cout<< "after Reset sp2.\n";
}

void Main ()
{
Test ();
}


The output of the program is as follows:
Copy Code code as follows:

The Sample now has 1 references
The Sample now has 2 references
After Reset SP1. The Sample now has 1 references
Destroying implementation
After Reset SP2.

As you can see, boost::shared_ptr pointers SP1 and SP2 also have access to implementation objects, and the memory of the objects it manages is automatically freed when both SP1 and SP2 release ownership of the object. The access rights of shared objects also enable the automatic management of their memory.

BOOST::SHARED_PTR's memory management mechanism:
Boost::shared_ptr's management mechanism is not complex, that is, the management of the object is a reference count, when the new boost::shared_ptr to manage the object, the object's reference count plus one; reduce a boost::shared_ When the object is managed by PTR, the reference count of the object is reduced by one, and if the reference count of the object is 0, it is not managed by any pointer to call Delete to release the memory it occupies.

The example above can be illustrated as follows:

1.SP1 manages the implementation object with a reference count of 1

2. Increase the SP2 to manage the implementation object and increase the reference count to 2

3.SP1 frees the implementation object to be managed with a reference count of 1

4.SP2 frees the implementation object for management, its reference count becomes 0, and the object is automatically deleted

Characteristics of Boost::shared_ptr:
Compared to the previous boost::scoped_ptr, BOOST::SHARED_PTR can share ownership of objects, so there is little scope for their use (or some usage rules to follow, as described below), which can be used in STL containers. In addition, it is thread-safe, and this is also important in multithreaded programs.

BOOST::SHARED_PTR Rules of Use:
Boost::shared_ptr is not absolutely safe, the following rules make it safer to use boost::shared_ptr:

1. Avoid direct memory management operations on objects managed by shared_ptr, so as not to cause the object to be released again
2.shared_ptr does not automatically manage the object memory of a circular reference (this is a common problem with various other reference count managed memory methods).
3. Do not construct a temporary shared_ptr as a function parameter.

The following code can cause a memory leak:

Copy Code code as follows:

void Test ()
{
Foo (boost::shared_ptr<implementation> (New Implementation ()), G ());
}
The correct usage is:
void Test ()
{
Boost::shared_ptr<implementation> SP (new Implementation ());
Foo (sp,g ());
}

three. weak_ptr

Circular reference:
Reference counting is a convenient memory management mechanism, but it has a great disadvantage, that is, the object that cannot manage circular references. A simple example is as follows:

Copy Code code as follows:

#include <string>
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>

Class parent;
class children;

typedef boost::shared_ptr<parent> PARENT_PTR;
typedef boost::shared_ptr<children> CHILDREN_PTR;

Class Parent
{
Public
~parent () {std::cout << "destroying parent\n";}

Public
Children_ptr children;
};

Class children
{
Public
~children () {std::cout << "destroying children\n";}

Public
Parent_ptr parent;
};


void Test ()
{
Parent_ptr father (new parent ());
Children_ptr Son (new children);

Father->children = Son;
Son->parent = Father;
}

void Main ()
{
std::cout<< "Begin test...\n";
Test ();
std::cout<< "End test.\n";
}


Run the program to see that even after the test function is exited, since the parent and children objects refer to each other, their reference count is 1 and cannot be automatically freed, and the two objects are no longer accessible. This leads to the infamous memory leak in C + +.

Generally speaking, there are three possible ways to remove this circular reference:
1. When only the last reference is left, you need to manually break the circular reference to release the object.
2. When the lifetime of the parent exceeds the lifetime of children, children instead uses a normal pointer to point to parent.
3. Use smart pointers with weak references to break this circular reference.

Although these three methods are feasible, both Method 1 and Method 2 require manual control by the programmer, which is cumbersome and error-prone. Here is a brief introduction to the third method and the weak reference smart pointer boost::weak_ptr in boost.

Strong references and weak references
A strong reference if the referenced object is alive, the reference also exists (that is, when at least one strong reference is present, the object cannot be released). Boost::share_ptr is a strong reference.

Weak references do not necessarily exist when the referenced object is alive. It's just a reference when it's there. A weak reference does not modify the reference count of the object, which means that the weak reference does not manage the object's memory and is functionally similar to a normal pointer, whereas a weak reference can detect whether the managed object has been freed, thereby avoiding access to illegal memory.

Copy Code code as follows:

Boost::weak_ptr

Boost::weak_ptr<t> is a weak-referenced smart pointer provided by boost, and its declaration can be simplified as follows:

Namespace Boost {

Template<typename T> class Weak_ptr {
Public
Template <typename y>
weak_ptr (const shared_ptr<y>& R);

weak_ptr (const weak_ptr& R);

~weak_ptr ();

t* get () const;
BOOL expired () const;
Shared_ptr<t> lock () const;
};
}


As you can see, boost::weak_ptr must be converted from a boost::share_ptr or another boost::weak_ptr, which means that the memory management of the object is the boost::share_ptr of that strong reference. Boost::weak_ptr only provides a means of access to management objects.

Boost::weak_ptr In addition to the basic access functionality of the managed objects (through the Get () function), there are two common functional functions: expired () is used to detect whether the managed object has been released, and lock () is used to get the strong reference pointer to the managed object.

To break the circular reference by boost::weak_ptr
Because a weak reference does not change the reference count, like a normal pointer, you can disassociate a circular reference by using a weak reference to the side of the circular reference. For the example above, you can disassociate the circular reference by changing the definition of children to the following:

Copy Code code as follows:

Class children
{
Public
~children () {std::cout << "destroying children\n";}

Public
Boost::weak_ptr<parent> parent;
};


Finally, it is worth mentioning that although the circular reference can be effectively lifted by a weak reference pointer, however, this method must be used when the programmer can foresee a circular reference, or this is just a compile-time solution, or it can cause a memory leak if a circular reference occurs during the process. Therefore, do not think that as long as the use of smart pointers can eliminate memory leaks. After all, for C + +, because there is no garbage collection mechanism, the memory leak for every programmer is a very headache problem.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.