Shared_from_this () is a member function of enable_shared_from_this <t> and returns shared_ptr <t>. Note that this function can be used only after the shared_ptr <t> constructor is called. The reason is that enable_shared_from_this: weak_ptr is not set in the constructor, but in the constructor of shared_ptr <t>.
The following code is incorrect:
- Class D: Public boost: enable_shared_from_this <D>
- {
- Public:
- D ()
- {
- Boost: shared_ptr <D> P = shared_from_this ();
- }
- };
Copy code
The original cause is very simple. Although the constructor of enable_shared_from_this <D> can be called in the constructor of D, weak_ptr is not set as mentioned earlier.
The following code is also incorrect:
- Class D: Public boost: enable_shared_from_this <D>
- {
- Public:
- Void func ()
- {
- Boost: shared_ptr <D> P = shared_from_this ();
- }
- };
- Void main ()
- {
- D;
- D. func ();
- }
Copy code
The error is due to the same reason.
The following code is correct:
- Void main ()
- {
- Boost: shared_ptr <D> D (new D );
- D-> func ();
- }
Copy code
In this example, boost: shared_ptr <D> D (new D) actually executes three actions: first, call the constructor of enable_shared_from_this <D>, and then call the constructor of D; finally, the constructor of shared_ptr <D> is called. It is the weak_ptr of enable_shared_from_this <D> set for 3rd actions, instead of 1st actions. This part is against the common sense and logic of C ++ and must be careful.
The conclusion is that you should not use shared_from_this In the constructor. Second, if you want to use shared_ptr, you should use it in all places. Instead of using D, you should never pass bare pointers.
Another note is that there cannot be two or more enable_shared_from_this <t> in the inheritance tree of the class. For example, the following code is incorrect:
- Class A: Public boost: enable_shared_from_this <A>
- {
- Public:
- A (): A (1 ){}
- Virtual ~ A (){}
- Boost: shared_ptr <A> get_ptra () {return shared_from_this ();}
- Int;
- };
- Class B: Public A, public boost: enable_shared_from_this <B>
- {
- Public:
- B (): B (2 ){}
- Boost: shared_ptr <B> get_ptrb ()
- {
- Return boost: enable_shared_from_this <B >:: shared_from_this ();
- }
- Int B;
- };
- Int _ tmain (INT argc, _ tchar * argv [])
- {
- {
- Boost: shared_ptr <B> X (new B );
- Boost: shared_ptr <A> A1 = x-> get_ptra ();
- Boost: shared_ptr <B> b1 = x-> get_ptrb ();
- }
- Return 0;
- }
Copy code
Note that in the above Code, B has two base classes of enable_shared_from_this, one is enable_shared_from_this <A>, and the other is enable_shared_from_this <B>. In the boost: shared_ptr <B> X (new B); line of code, the shared_ptr <B> constructor sets only one weak_ptr of the two base classes. In the preceding example, only enable_shared_from_this <A> is set. If you modify B's definition:
Class B: Public boost: enable_shared_from_this <B>, public,
Set only weak_ptr of enable_shared_from_this <B>. Obviously, they are all incorrect.
So why do enable_shared_from_this and shared_ptr need to be implemented in this way? Why is there such a weird result?
First, evaluate the shared_ptr constructor:
- Template <class Y>
- Explicit shared_ptr (y * P): Px (P), Pn (p) // y must be complete
- {
- Boost: detail: sp_enable_shared_from_this (Pn, P, P );
- }
- Template <class T, class Y> void sp_enable_shared_from_this (shared_count const & Pn, boost: enable_shared_from_this <t> const * PE, y const * px)
- {
- If (PE! = 0) Pe-> _ internal_weak_this. _ internal_assign (const_cast <y *> (PX), PN );
- }
Copy code
Note that sp_enable_shared_from_this is a template function and is called only once. Therefore, it is impossible to assign values to weak_ptr of two enable_shared_from_this base classes. But the problem is that the result is different after B's definition is changed. Here is a very obscure compiler bug. In principle, when compiling this code, the compiler should note that it cannot really decide how to instantiate sp_enable_shared_from_this and report an error. However, VC 2008 does not report an error, but compiled the code. (G ++ will report an error here)
So what is the correct solution?
- Class B: public
- {
- Public:
- B (): B (2 ){}
- Boost: shared_ptr <B> get_ptrb ()
- {
- Return boost: dynamic_pointer_cast <B> (shared_from_this ());
- }
- Int B;
- };
Copy code
Note that B does not directly inherit enable_shared_from_this, but uses dynamic_pointer_cast to convert the type.
For how enable_shared_from_this is implemented, see the original article:
Every enable_shared_from_this base contains a weak_ptr, The shared_ptr constructor looks up the enable_shared_from_this base and initializes its weak_ptr accordingly. This doesn't work when there are
Two or more enable_shared_from_this bases, though.
I cocould put the weak_ptr in a virtual polymorphic base. This wocould force polymorphism on all clients of enable_shared_from_this... probably acceptable. It will also force a dynamic_pointer_cast in every
Shared_from_this, and this may be harder to swallow, especially in cases where rtti is off. So I'm not sure.
If you do want the above behavior, it's easy to duplicate, as I already responded in my first post on the topic. just make foob return dynamic_pointer_cast <B> (fooa () and remove the enable_shared_from_this <B>
Base (A needs to be made polymorphic, of course ).
Note that in order for dynamic_pointer_cast to work, a must have a virtual function. The simplest practice is to assign the number of destructor to a virtual function (if a class is expected to be inherited, the Destructor should be a virtual function ).
Shared_from_this is worth noting.