Recently, the project needs to manage resources in multiple threads. Naturally, it comes to the idea of using smart pointers with reference counting technology to construct a garbage collection and recycling mechanism. The first consideration is the use of smartptr in Loki, which is already running in the project. Now we can see that Loki: smartptr is not as flexible as we think. The problem is that the constructor of smartptr (uses the original pointer to construct a smart pointer object ):
Smartptr (const storedtype & P): SP (P)
{
Smartptrguard kpguard (* This, & smartptr: onkpreject );
Kp: oninit (getimpl (* This ));
Kpguard. Dismiss ();
}
When you pass in a raw pointer to smartptr, the constructor is called. This constructor does not execute an increment operation for reference counting. For example, when you write the following code:
Class CA;
Void fun ()
{
Ca * PCA = new CA; // The reference count is 1.
LOKI: smartptr <Ca> SPCA1 (PA); // The reference count is still 1
LOKI: smartptr <Ca> SPCA 2 (PA); // The reference count is still 1
}
What will happen? The default ownership policy of smartptr is refcounted. Before fun returns the result, the reference count is always 1. However, when fun returns the result, it executes the destructor of spa1 and spc2, both SPCA1 and SPCA decrease the reference count at a time. Once but twice, the problem arises.
Smartptr constructor does not perform addref once, but each destructor does not hesitate to execute release once.
Of course, this problem can be easily solved. Every time you use the original pointer to construct smartptr, you call addref. For example, the fun function writes:
Void fun ()
{
Ca * PCA = new CA; // The reference count is 1.
LOKI: smartptr <Ca> SPCA1 (PA); // The reference count is still 1
LOKI: smartptr <Ca> SPCA 2 (PA); // The reference count is still 1
SPCA 2-> addref (); // The reference count is 2.
}
Also, note that addref cannot be called after the SPCA1 construction is complete; otherwise, an additional increment is made. This solution is ugly. One of the purposes of using a smart pointer is to make it
Resources have been managed. When both internal and external resources are involved in resource management, it becomes messy. Even more depressing, I have found that such problems cannot be solved by customizing relevant policies. SMA
The rtptr (const storedtype & P) constructor does not execute the OP: clone operation once like its copy constructor (addref is called internally ). finally, it is easy to solve this problem by modifying the Loki source code. Add an OP: Clone () at the end of the smartptr (const storedtype & P) function (); in addition, when the refcounted policy is constructed, the refcount is initialized to 0;
Boost's intrusive_ptr does this (boost has several smart pointer templates, because I only care about the intrusive reference counting method, so I only read this implementation :():
Intrusive_ptr (T * P, bool add_ref = true): P _ (p)
{
If (P _! = 0 & add_ref) intrusive_ptr_add_ref (P _);
}
Boost sends the question of constructing a smart pointer with the original pointer to the user to determine whether to add the pointer once. By default, it executes the addref command once.
Loki, known for its strength and flexibility, has made me depressed. Maybe this is the difference in design concepts.