shared

zhaozj2021-02-16  58

Shared_ptr Source Code Interpretation

Rayleahaan@hotmail.com

1 Introduction

As is well known, auto_ptr cannot meet the requirements of the standard container for elements due to its destructive copying semantics, so it cannot be placed in a standard container; if we want to automatically remove the object referred to by the pointer element it accommodate when the container is destructed It usually uses some indirect ways to achieve, which is more cumbersome. A new type of smart pointer Shared_PTR is provided in the Boost library, which solves the problem of sharing object ownership between multiple normings, and also meets the requirements of the container to elements, so it can be safely placed in the container. Now we can write this:

Vector > books;

Books.push_back (shared_ptr ));

2 implementation

How is Shared_Ptr? Let's analyze its source code: Follow the above code, after the Book object is created, create a temporary shared_ptr object, the constructor of Shared_PTR is called:

Template

Explicit Shared_Ptr (Y * P)

: PX (P), PN (p, checked_deleter ())

{

Detail :: sp_enable_shared_from_this (p, p, pn);

}

Obviously this is a template function, and the "The Y should be a BOOK type, the PX and PN for member variables of Shared_PTR, which is as follows:

Template Class Shared_ptr

{

Private:

T * px; // Contained Pointer

Detail :: Shared_Count Pn; // Reference Counter

}

Since we use BOOK for template parameters to instant Shared_Ptr (Shared_Ptr ), the PX should be the BOK * type, PX (P) initializes the PX to point to the creating Book object. The type of PN member variable for shared_count is initialized by two parameters, one is the incoming Book object pointer, the other is a temporary check_deleter object, the SHARED_COUNT constructor is called:

Template

Shared_count (P, D D)

: pi_ (0)

{

Try

{

PI_ = new sp_counted_base_impl (p, d);

}

Catch (...)

{

D (p); // delete P

Throw;

}

}

The P is Book * type, D is the checkage_deleter type. In the constructor of Shared_Count, a SP_COUNTED_BASE_IMPL object is created, with the incoming Book object pointer and the check_deleter object as constructor parameters. It looks sp_counted_base_impl like an implementation class:

Template

Class sp_counted_base_impl: public sp_counted_base

{

Private:

P PTR; // Copy Constructor Must Not throwd Del; // Copy Constructor Must Not throw

PUBLIC:

SP_COUNTED_BASE_IMPL (P, D D): PTR (P), Del (D)

{

}

}

SP_COUNTED_BASE constructor should be called first:

Class sp_counted_base {

PUBLIC:

SP_COUNTED_BASE (): use_count_ (1), weak_count_ (1)

{

}

Private:

Long use_count_; // #shared

Long weak_count_; // #Weak (#shared! = 0)

}

It seems that sp_counted_base is where the reference count is saved, where USE_COUNT_ and WEAK_COUNT_ are initialized to 1. Next, the constructor of sp_counted_base_impl saves the pointer of the Book object and the check_deleter object. The relationship between several major classes is expressed:

When books.push_back is called, a copy constructor should occur:

Template

Shared_ptr (Shared_Ptr Const & R)

: PX (R.PX), PN (R.PN) // NEVER THROWS

{}

Pn is a shared_count type, and its copy constructor is called:

Shared_count (Shared_Count Const & R)

: pi_ (r.pi_) // Nothrow

{

IF (pi _! = 0) pi _-> add_ref_copy ();

}

It can be seen that the newly created Shared_PTR object and the copied shared_ptr object have a pointer to the same sp_counted_base object, and add the reference count by calling sp_count_base's add_ref_copy function:

Void add_ref_copy () { USE_COUNT_;}

Use the object map to indicate this moment of this moment:

When the temporary Share_ptr object is copied into the container, it should be destroyed, because there is no explicit definition patriarf function, the destructor generated by the compiler will sequence PN member:

~ shared_count () // nothrow

{

IF (pi_! = 0) pi _-> release ();

}

Shared_counted_base's Release function:

Void release () // nothrow

{

{

Long new_use_count = - rsE_count_;

IF (new_use_count! = 0) return;

}

Dispose ();

Weak_release ();

}

Here, the reference count saved by sp_counted_base is reduced, and the reference count is reduced to 1 and return. So the temporary shared_ptr object was destroyed, but the Book object was not destroyed. When the shared_ptr object in the vector is also destructed, the reference count will be reduced to 0, so the DISPOSE function is executed:

Virtual void dispose () = 0; // nothrow

Pure virtual function? Don't forget the object type of PI_ actually pointing to sp_counted_base_impl, so sp_counted_base_impl's Dispose function is called:

Virtual void dispose () // nothrow {

Del (PTR);

}

According to the previous analysis, DEL is a check_deleter object:

Template

Struct checked_deleter {

Typedef void result_type;

TypeDef t * argument_type;

Void Operator () (t * x) const

{

// boost :: Disables ADL

Boost :: checked_delete (x);

}

}

It seems to be a Function Object, which is incorporated into the pointer of the book object, and removes the Book object of Shared_PTR management by calling the check_delete function. You can see that Check_Deleter does not have any member variables, so the copy structure that occurs above should be no overhead. SP_COUNTED_BASE and SP_COUNTED_BASE_IMPL seem to be used? Yes, it is Template Method, which is reused by the algorithm of the reference count independently of the implementation details of the object deletion. Shared_ptr is a thread safe? Yes, it uses a lightweight MUTEX to synchronize, for simplicity, I don't list the relevant code, it is actually relatively simple. As for efficiency, it seems to be much more operation, will it be slower? Experience tells us: Do not do prior optimization. When you really find the performance bottleneck, you will be more targeted. For some resources, it is represented by a pointer, but it is necessary to release in a specific manner, such as a file handle, is there any way to manage? The answer is yes, you only need to provide a function or function object to implement that specific release logic, then pass it in constructing the Shared_PTR object:

Void file_closer (file * f) {fclose (f);

Shared_ptr file (FOPEN ("/ a.txt", "r"), file_closer;

Here, the second template constructor of Shared_PTR works:

Template

Class D> Shared_PTR (Y * P, D D)

: PX (P), PN (P, D)

{

Detail :: sp_enable_shared_from_this (p, p, pn);

}

Detecting D should be a VOID (*) function pointer type, when the reference count on the file handle is 0, file_closer will be called, thereby closing the file.

3 conclusions

Shared_ptr solves the problem of sharing object ownership between multiple normings, which can be safely placed in a standard container and is a thread.

Last Modified: Saturday, March 26th, 2005

HTML Conversion by

TEX2PAGE 2005-02-27

转载请注明原文地址:https://www.9cbs.com/read-22721.html

New Post(0)