Shared_from_this is worth noting.

Source: Internet
Author: User

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:

  1. Class D: Public boost: enable_shared_from_this <D>
  2. {
  3. Public:
  4. D ()
  5. {
  6. Boost: shared_ptr <D> P = shared_from_this ();
  7. }
  8. };
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:

  1. Class D: Public boost: enable_shared_from_this <D>
  2. {
  3. Public:
  4. Void func ()
  5. {
  6. Boost: shared_ptr <D> P = shared_from_this ();
  7. }
  8. };
  9. Void main ()
  10. {
  11. D;
  12. D. func ();
  13. }
Copy code

The error is due to the same reason.

The following code is correct:

  1. Void main ()
  2. {
  3. Boost: shared_ptr <D> D (new D );
  4. D-> func ();
  5. }
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:

  1. Class A: Public boost: enable_shared_from_this <A>
  2. {
  3. Public:
  4. A (): A (1 ){}
  5. Virtual ~ A (){}
  6. Boost: shared_ptr <A> get_ptra () {return shared_from_this ();}
  7. Int;
  8. };
  9. Class B: Public A, public boost: enable_shared_from_this <B>
  10. {
  11. Public:
  12. B (): B (2 ){}
  13. Boost: shared_ptr <B> get_ptrb ()
  14. {
  15. Return boost: enable_shared_from_this <B >:: shared_from_this ();
  16. }
  17. Int B;
  18. };
  19. Int _ tmain (INT argc, _ tchar * argv [])
  20. {
  21. {
  22. Boost: shared_ptr <B> X (new B );
  23. Boost: shared_ptr <A> A1 = x-> get_ptra ();
  24. Boost: shared_ptr <B> b1 = x-> get_ptrb ();
  25. }
  26. Return 0;
  27. }
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:

  1. Template <class Y>
  2. Explicit shared_ptr (y * P): Px (P), Pn (p) // y must be complete
  3. {
  4. Boost: detail: sp_enable_shared_from_this (Pn, P, P );
  5. }
  6. 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)
  7. {
  8. If (PE! = 0) Pe-> _ internal_weak_this. _ internal_assign (const_cast <y *> (PX), PN );
  9. }
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?

  1. Class B: public
  2. {
  3. Public:
  4. B (): B (2 ){}
  5. Boost: shared_ptr <B> get_ptrb ()
  6. {
  7. Return boost: dynamic_pointer_cast <B> (shared_from_this ());
  8. }
  9. Int B;
  10. };
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.

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.