|
(A) RAII mechanism
Mechanism RAII (resource acquisition is initialization, Resource Acquisition Is Initialization), application resources in the constructor use of resources of the class, and then use the last release of resources in the destructor.
If the object is created on the stack it (such as a local object), then RAAII mechanism would work, when the end of the life cycle of an object invokes its destructor to free up resources. But when the object is created on the heap (with the new operator), then the order of the object destructor memory is required to call the delete operator. Dangers This this way, when we forgot to delete after new will cause a memory leak.
(B) the smart pointers
boost.smart_ptr library provides six smart pointers, including: scoped_ptr, scoped_array, shared_ptr, shared_array, weak_ptr and intrusive_ptr. When using these smart pointers required template type T's destructor can not throw.
To use these smart pointers, you need to join accession:
#include < boost / smart_ptr.hpp>
// Using namespace boost;
(1) scoped_ptr
scoped_ptr packaging the new operator dynamically allocated on the heap object, which has strict ownership, that it can not transfer the wrapped object pointer, once scoped_ptr get over the management of the object, you can not take it back from there. Like its name, as the smart pointers can only be used in this scope, and did not want to be transferred.
Scoped_ptr look at the source code:
template < class T > class scoped_ptr // noncopyable {
private:
T * px;
scoped_ptr (scoped_ptr const &);
scoped_ptr & operator = (scoped_ptr const &);
typedef scoped_ptr < T > this_type;
void operator == (scoped_ptr const &) const;
! Void operator = (scoped_ptr const &) const;
public:
typedef T element_type;
explicit scoped_ptr (T * p = 0): px (p) // never throws {
#if defined (BOOST_SP_ENABLE_DEBUG_HOOKS)
boost :: sp_scalar_constructor_hook (px);
#endif
}
#ifndef BOOST_NO_AUTO_PTR
explicit scoped_ptr (std :: auto_ptr < T > p) BOOST_NOEXCEPT: px (p.release ()) {
#if defined (BOOST_SP_ENABLE_DEBUG_HOOKS)
boost :: sp_scalar_constructor_hook (px);
#endif
}
#endif
~ Scoped_ptr () // never throws {
#if defined (BOOST_SP_ENABLE_DEBUG_HOOKS)
boost :: sp_scalar_destructor_hook (px);
#endif
boost :: checked_delete (px);
}
void reset (T * p = 0) // never throws {
BOOST_ASSERT (p == 0 || p = px!); // Catch self-reset errors
this_type (p) .swap (* this);
}
T & operator * () const // never throws {
BOOST_ASSERT (px = 0!);
return * px;
}
T * operator -> () const // never throws {
BOOST_ASSERT (px = 0!);
return px;
}
T * get () const BOOST_NOEXCEPT {
return px;
}
#include < boost / smart_ptr / detail / operator_bool.hpp>
void swap (scoped_ptr & b) BOOST_NOEXCEPT {
T * tmp = b.px;
b.px = px;
px = tmp;
}
};
Scoped_ptr can see the copy constructor and assignment operator (=) are declared as private, thus ensuring scoped_ptr of noncopyable, but also to ensure its management pointer can not be transferred. Also note scoped_ptr can not be compared, because of its two overloaded comparison operators are private.
Note: Due to scoped_ptr not copy and assignment, so it can not be used as elements of the container.
(2) scoped_array
scoped_array like scoped_ptr, its packaging is new [] and delete [] operator.
Here is scoped_ptr part of the source code:
template < class T > class scoped_array // noncopyable {
private:
T * px;
scoped_array (scoped_array const &);
scoped_array & operator = (scoped_array const &);
typedef scoped_array < T > this_type;
void operator == (scoped_array const &) const;
! Void operator = (scoped_array const &) const;
public:
typedef T element_type;
explicit scoped_array (T * p = 0) BOOST_NOEXCEPT: px (p) {
#if defined (BOOST_SP_ENABLE_DEBUG_HOOKS)
boost :: sp_array_constructor_hook (px);
#endif
}
~ Scoped_array () // never throws {
#if defined (BOOST_SP_ENABLE_DEBUG_HOOKS)
boost :: sp_array_destructor_hook (px);
#endif
boost :: checked_array_delete (px);
}
void reset (T * p = 0) // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) {
BOOST_ASSERT (p == 0 || p = px!); // Catch self-reset errors
this_type (p) .swap (* this);
}
T & operator [] (std :: ptrdiff_t i) const // never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT) {
BOOST_ASSERT (px = 0!);
BOOST_ASSERT (i> = 0);
return px [i];
}
T * get () const BOOST_NOEXCEPT {
return px;
}
#include < boost / smart_ptr / detail / operator_bool.hpp>
void swap (scoped_array & b) BOOST_NOEXCEPT {
T * tmp = b.px;
b.px = px;
px = tmp;
}
};
Note:
• constructor accepts the new [] results
• * and not overloaded -> operator;
• Providing operator [] operator overloading, you can use the same as ordinary arrays;
• not begin (), end () iterator.
Recommendation: scoped_ptr use or some inflexible First, it provides a pointer value in the form of an array of all the need to use or when to use std :: vector container instead of scoped_ptr better.
(3) shared_ptr
shared_ptr is also packed new operator, but it is the most important point is that it implements the reference counting, so it can be copied and assigned freely, with its name can be shared, when there is no code to use (that is, the reference count is zero time), it was deleted dynamically allocated memory object to be packaged. It can be used as elements of the container.
The following are some of its source code:
template < class T > class shared_ptr {
private:
typedef shared_ptr < T > this_type;
public:
typedef typename boost :: detail :: sp_element < T > :: type element_type;
shared_ptr () BOOST_NOEXCEPT: px (0), pn () {}
template < class Y > explicit shared_ptr (Y * p): px (p), pn () // Y must be complete
{Boost :: detail :: sp_pointer_construct (this, p, pn);}
template < class Y, class D > shared_ptr (Y * p, D d): px (p), pn (p, d)
{Boost :: detail :: sp_deleter_construct (this, p);}
// As above, but with allocator. A's copy constructor shall not throw.
template < class Y, class D, class A > shared_ptr (Y * p, D d, A a): px (p), pn (p, d, a)
{Boost :: detail :: sp_deleter_construct (this, p);}
template < class Y >
explicit shared_ptr (weak_ptr < Y > const & r): pn (r.pn) // may throw {
boost :: detail :: sp_assert_convertible < Y, T > ();
// It is now safe to copy r.px, as pn (r.pn) did not throw
px = r.px;
}
template < class Y >
shared_ptr (weak_ptr < Y > const & r, boost :: detail :: sp_nothrow_tag)
BOOST_NOEXCEPT: px (0), pn (r.pn, boost :: detail :: sp_nothrow_tag ()) {
if (! pn.empty ()) {
px = r.px;
}
}
template < class Y >
shared_ptr (shared_ptr < Y > const & r)
BOOST_NOEXCEPT: px (r.px), pn (r.pn)
{Boost :: detail :: sp_assert_convertible ();}
template < class Y >
shared_ptr (shared_ptr < Y > const & r, element_type * p) BOOST_NOEXCEPT: px (p), pn (r.pn) {}
template < class Y, class D >
shared_ptr (boost :: movelib :: unique_ptr < Y, D > r): px (r.get ()), pn () {
boost :: detail :: sp_assert_convertible < Y, T > ();
typename boost :: movelib :: unique_ptr < Y, D > :: pointer tmp = r.get ();
pn = boost :: detail :: shared_count (r);
boost :: detail :: sp_deleter_construct (this, tmp);
}
shared_ptr & operator = (shared_ptr const & r) BOOST_NOEXCEPT
{This_type (r) .swap (* this); return * this;}
template < class Y, class D >
shared_ptr & operator = (boost :: movelib :: unique_ptr < Y, D > r) {
boost :: detail :: sp_assert_convertible < Y, T > ();
typename boost :: movelib :: unique_ptr < Y, D > :: pointer p = r.get ();
shared_ptr tmp;
tmp.px = p;
tmp.pn = boost :: detail :: shared_count (r);
boost :: detail :: sp_deleter_construct (& tmp, p);
tmp.swap (* this);
return * this;
}
void reset () BOOST_NOEXCEPT // never throws in 1.30+
{This_type () swap (* this);.}
template < class Y > void reset (Y * p) // Y must be complete {
BOOST_ASSERT (p == 0 || p = px!); // Catch self-reset errors
this_type (p) .swap (* this);
}
template < class Y, class D > void reset (Y * p, D d)
{This_type (p, d) .swap (* this);}
template < class Y, class D, class A > void reset (Y * p, D d, A a)
{This_type (p, d, a) .swap (* this);}
template < class Y > void reset (shared_ptr const & r, element_type * p)
{This_type (r, p) .swap (* this);}
// Never throws (but has a BOOST_ASSERT in it, so not marked with BOOST_NOEXCEPT)
typename boost :: detail :: sp_array_access < T > :: type operator [] (std :: ptrdiff_t i) const {
BOOST_ASSERT (px = 0!);
BOOST_ASSERT (i> = 0 && (i :: value || boost :: detail :: sp_extent < T > :: value == 0));
return static_cast < typename boost :: detail :: sp_array_access < T > :: type > (px [i]);
}
element_type * get () const BOOST_NOEXCEPT
{Return px;}
// Implicit conversion to "bool"
#include < boost / smart_ptr / detail / operator_bool.hpp>
bool unique () const BOOST_NOEXCEPT
{Return pn.unique ();}
long use_count () const BOOST_NOEXCEPT
{Return pn.use_count ();}
void swap (shared_ptr & other) BOOST_NOEXCEPT
{Std :: swap (px, other.px); pn.swap (other.pn);}
private:
template < class Y > friend class shared_ptr;
template < class Y > friend class weak_ptr;
#endif
element_type * px; // contained pointer
boost :: detail :: shared_count pn; // reference counter
};
You can not use static_cast < T * > (sp.get ()) This form will be managed by a shared_ptr pointers display conversion, but also provides a shared_ptr static_pointer_cast < T > (), const_pointer_cast < T > () and dynamic_pointer_cast < T > ( ) corresponding to several member functions. It should also be using the unique (), NA use_count () == 1 in the form.
Also creating shared_ptr can be used when the factory function to create (make_shared < T > ()), which is located in the file make_shared.hpp. When you need to use:
#include < boost / make_shared.hpp >
This is one of make_shared ways:
template < class T, class ... Args > typename boost :: detail :: sp_if_not_array < T > :: type make_shared (Args && ... args)
{
boost :: shared_ptr < T > pt (static_cast < T * > (0), BOOST_SP_MSD (T));
boost :: detail :: sp_ms_deleter < T > * pd = static_cast < boost :: detail :: sp_ms_deleter < T > * > (pt._internal_get_untyped_deleter ());
void * pv = pd-> address ();
:: New (pv) T (boost :: detail :: sp_forward < Args > (args) ...);
pd-> set_initialized ();
T * pt2 = static_cast < T * > (pv);
boost :: detail :: sp_enable_shared_from_this (& pt, pt2, pt2);
return boost :: shared_ptr < T > (pt, pt2);
}
Note: There are a lot of knowledge about shared_ptr point. . .
(4) weak_ptr
weak_ptr is a smart pointer to tie shared_ptr introduced, the behavior does not have an ordinary pointer, and it does not override operator * and -> operators. For observing the usage share_ptr in the management of resources.
template < class T > class weak_ptr
{
private:
// Borland 5.5.1 specific workarounds
typedef weak_ptr < T > this_type;
public:
typedef typename boost :: detail :: sp_element < T > :: type element_type;
weak_ptr () BOOST_NOEXCEPT: px (0), pn () // never throws in 1.30+ {}
// Generated copy constructor, assignment, destructor are fine ...
#if! defined (BOOST_NO_CXX11_RVALUE_REFERENCES)
// ... Except in C ++ 0x, move disables the implicit copy
weak_ptr (weak_ptr const & r) BOOST_NOEXCEPT: px (r.px), pn (r.pn) {}
weak_ptr & operator = (weak_ptr const & r) BOOST_NOEXCEPT {
px = r.px;
pn = r.pn;
return * this;
}
#endif
template < class Y >
#if! defined (BOOST_SP_NO_SP_CONVERTIBLE)
weak_ptr (weak_ptr < Y> const & r, typename boost :: detail :: sp_enable_if_convertible < Y, T> :: type = boost :: detail :: sp_empty ())
#else
weak_ptr (weak_ptr < Y> const & r)
#endif
BOOST_NOEXCEPT: px (. R.lock () get ()), pn (r.pn) {boost :: detail :: sp_assert_convertible < Y, T> ();}
#if! defined (BOOST_NO_CXX11_RVALUE_REFERENCES)
template < class Y>
#if! defined (BOOST_SP_NO_SP_CONVERTIBLE)
weak_ptr (weak_ptr < Y> && r, typename boost :: detail :: sp_enable_if_convertible < Y, T> :: type = boost :: detail :: sp_empty ())
#else
weak_ptr (weak_ptr < Y> && r)
#endif
BOOST_NOEXCEPT: px (. R.lock () get ()), pn (static_cast (r.pn)) {
boost :: detail :: sp_assert_convertible < Y, T> ();
r.px = 0;
}
// For better efficiency in the T == Y case
weak_ptr (weak_ptr && r)
BOOST_NOEXCEPT: px (r.px), pn (static_cast < boost :: detail :: weak_count &&> (r.pn)) {r.px = 0;}
// For better efficiency in the T == Y case
weak_ptr & operator = (weak_ptr && r) BOOST_NOEXCEPT {
this_type (static_cast (r)) .swap (* this);
return * this;
}
#endif
template < class Y>
#if! defined (BOOST_SP_NO_SP_CONVERTIBLE)
weak_ptr (shared_ptr < Y> const & r, typename boost :: detail :: sp_enable_if_convertible < Y, T> :: type = boost :: detail :: sp_empty ())
#else
weak_ptr (shared_ptr < Y> const & r)
#endif
BOOST_NOEXCEPT: px (r.px), pn (r.pn) {
boost :: detail :: sp_assert_convertible < Y, T> ();
}
#if! defined (BOOST_MSVC) || (BOOST_MSVC> = 1300)
template < class Y>
weak_ptr & operator = (weak_ptr < Y> const & r) BOOST_NOEXCEPT {
boost :: detail :: sp_assert_convertible ();
px = r.lock () get ().;
pn = r.pn;
return * this;
}
#if! defined (BOOST_NO_CXX11_RVALUE_REFERENCES)
template < class Y>
weak_ptr & operator = (weak_ptr < Y> && r) BOOST_NOEXCEPT {
this_type (static_cast &&> (r)) .swap (* this);
return * this;
}
#endif
template < class Y>
weak_ptr & operator = (shared_ptr < Y> const & r) BOOST_NOEXCEPT {
boost :: detail :: sp_assert_convertible < Y, T> ();
px = r.px;
pn = r.pn;
return * this;
}
#endif
shared_ptr < T> lock () const BOOST_NOEXCEPT {
return shared_ptr < T> (* this, boost :: detail :: sp_nothrow_tag ());
}
long use_count () const BOOST_NOEXCEPT {return pn.use_count ();}
bool expired () const BOOST_NOEXCEPT {return pn.use_count () == 0;}
bool _empty () const // extension, not in std :: weak_ptr {return pn.empty ();}
void reset () BOOST_NOEXCEPT // never throws in 1.30+ {this_type () swap (* this);.}
void swap (this_type & other) BOOST_NOEXCEPT {
std :: swap (px, other.px);
pn.swap (other.pn);
}
template < typename Y>
void _internal_aliasing_assign (weak_ptr < Y> const & r, element_type * px2) {px = px2; pn = r.pn;}
template < class Y> bool owner_before (weak_ptr < Y> const & rhs) const BOOST_NOEXCEPT {return pn
template < class Y> bool owner_before (shared_ptr < Y> const & rhs) const BOOST_NOEXCEPT {return pn
// Tasteless as this may seem, making all members public allows member templates
// To work in the absence of member template friends. (Matthew Langston)
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
private:
template < class Y> friend class weak_ptr;
template < class Y> friend class shared_ptr;
#endif
element_type * px; // contained pointer
boost :: detail :: weak_count pn; // reference counter
}; // Weak_ptr
weak_ptr is designed to work with shared_ptr can be from one or another weak_ptr shared_ptr object construction, access to resources observation. But weak_ptr no shared resources, its structure does not cause an increase pointer reference count. Similarly, when weak_ptr destructor will not lead to a reduction reference count.
Use weak_ptr member function use_count () can get shared_ptr's reference count, another expired () function is equivalent to use_count () == 0, but faster, indicating the observed resources no longer exist.
Get this for shared_ptr:
In the file < boost / enable_shared_from_this.hpp> defines a enable_shared_from_this < T> class, it's a summary statement:
template < class T> class enable_shared_from_this {
protected:
enable_shared_from_this () BOOST_NOEXCEPT {}
enable_shared_from_this (enable_shared_from_this const &) BOOST_NOEXCEPT {}
enable_shared_from_this & operator = (enable_shared_from_this const &) BOOST_NOEXCEPT {return * this;}
~ Enable_shared_from_this () BOOST_NOEXCEPT {}
public:
shared_ptr < T> shared_from_this () {
shared_ptr < T> p (weak_this_);
BOOST_ASSERT (p.get () == this);
return p;
}
shared_ptr < T const> shared_from_this () const {
shared_ptr < T const> p (weak_this_);
BOOST_ASSERT (p.get () == this);
return p;
}
weak_ptr < T> weak_from_this () BOOST_NOEXCEPT {return weak_this_;}
weak_ptr < T const> weak_from_this () const BOOST_NOEXCEPT {return weak_this_;}
public: // actually private, but avoids compiler template friendship issues
// Note: invoked automatically by shared_ptr; do not call
template void _internal_accept_owner (shared_ptr < X> const * ppx, Y * py) const {
if (weak_this_.expired ()) {
weak_this_ = shared_ptr < T> (* ppx, py);
}
}
private:
mutable weak_ptr < T> weak_this_;
};
When in use simply want to make the management of inherited shared_ptr class from enable_shared_from_this, call the member function shared_form_this () will return to this in shared_ptr. E.g:
#include < boost / enable_shared_from_this.hpp>
#include < boost / make_shared.hpp>
#include < iostream>
class self_shared: public boost :: enable_shared_from_this < self_shared> {
public:
self_shared (int n): x (n) {}
int x;
void print () {
std :: cout << "self_shared:" << x << std :: endl;
}
};
int main (int argc, char * argv []) {
std :: shared_ptr < self_shared> sp = std :: make_shared (123);
sp-> print ();
std :: shared_ptr < self_shared> p = sp-> shared_from_this ();
p-> x = 100;
p-> print ();
return 0;
}
It should be noted: Do not use shared_from_this from an ordinary object (self_shared Object) () Gets shared_ptr, for example:
self_shared ss;
boost :: shared_ptr < self_shared> p = ss.shared_from_this ();
This will cause the program to run when an attempt to delete an object allocated on the stack when the shared_ptr destructor, undefined behavior occurs. |
|
|
|