1 //===----------------------------------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 // template<class T>
11 // class enable_shared_from_this
12 // {
13 // protected:
14 //     enable_shared_from_this();
15 //     enable_shared_from_this(enable_shared_from_this const&);
16 //     enable_shared_from_this& operator=(enable_shared_from_this const&);
17 //     ~enable_shared_from_this();
18 // public:
19 //     shared_ptr<T> shared_from_this();
20 //     shared_ptr<T const> shared_from_this() const;
21 //     weak_ptr<T> weak_from_this() noexcept;                         // C++17
22 //     weak_ptr<T const> weak_from_this() const noexecpt;             // C++17
23 // };
24 
25 #include <memory>
26 #include <cassert>
27 
28 #include "test_macros.h"
29 #include "count_new.hpp"
30 
31 struct T
32     : public std::enable_shared_from_this<T>
33 {
34 };
35 
36 struct Y : T {};
37 
38 struct Z : Y {};
39 
nullDeleter(void *)40 void nullDeleter(void*) {}
41 
42 struct Foo : virtual public std::enable_shared_from_this<Foo>
43 {
~FooFoo44     virtual ~Foo() {}
45 };
46 
47 struct Bar : public Foo {
BarBar48     Bar(int) {}
49 };
50 
51 
52 struct PrivateBase : private std::enable_shared_from_this<PrivateBase> {
53 };
54 
55 
main()56 int main()
57 {
58     {  // https://bugs.llvm.org/show_bug.cgi?id=18843
59     std::shared_ptr<T const> t1(new T);
60     std::shared_ptr<T const> t2(std::make_shared<T>());
61     }
62     { // https://bugs.llvm.org/show_bug.cgi?id=27115
63     int x = 42;
64     std::shared_ptr<Bar> t1(new Bar(42));
65     assert(t1->shared_from_this() == t1);
66     std::shared_ptr<Bar> t2(std::make_shared<Bar>(x));
67     assert(t2->shared_from_this() == t2);
68     }
69     {
70     std::shared_ptr<Y> p(new Z);
71     std::shared_ptr<T> q = p->shared_from_this();
72     assert(p == q);
73     assert(!p.owner_before(q) && !q.owner_before(p)); // p and q share ownership
74     }
75     {
76     std::shared_ptr<Y> p = std::make_shared<Z>();
77     std::shared_ptr<T> q = p->shared_from_this();
78     assert(p == q);
79     assert(!p.owner_before(q) && !q.owner_before(p)); // p and q share ownership
80     }
81     {
82       typedef std::shared_ptr<PrivateBase> APtr;
83       APtr a1 = std::make_shared<PrivateBase>();
84       assert(a1.use_count() == 1);
85     }
86     // Test LWG issue 2529. Only reset '__weak_ptr_' when it's already expired.
87     // https://cplusplus.github.io/LWG/lwg-defects.html#2529
88     // Test two different ways:
89     // * Using 'weak_from_this().expired()' in C++17.
90     // * Using 'shared_from_this()' in all dialects.
91     {
92         assert(globalMemCounter.checkOutstandingNewEq(0));
93         T* ptr = new T;
94         std::shared_ptr<T> s(ptr);
95         {
96             // Don't re-initialize the "enable_shared_from_this" base
97             // because it already references a non-expired shared_ptr.
98             std::shared_ptr<T> s2(ptr, &nullDeleter);
99         }
100 #if TEST_STD_VER > 14
101         // The enable_shared_from_this base should still be referencing
102         // the original shared_ptr.
103         assert(!ptr->weak_from_this().expired());
104 #endif
105 #ifndef TEST_HAS_NO_EXCEPTIONS
106         {
107             try {
108                 std::shared_ptr<T> new_s = ptr->shared_from_this();
109                 assert(new_s == s);
110             } catch (std::bad_weak_ptr const&) {
111                 assert(false);
112             } catch (...) {
113                 assert(false);
114             }
115         }
116 #endif
117         s.reset();
118         assert(globalMemCounter.checkOutstandingNewEq(0));
119     }
120     // Test LWG issue 2529 again. This time check that an expired pointer
121     // is replaced.
122     {
123         assert(globalMemCounter.checkOutstandingNewEq(0));
124         T* ptr = new T;
125         std::weak_ptr<T> weak;
126         {
127             std::shared_ptr<T> s(ptr, &nullDeleter);
128             assert(ptr->shared_from_this() == s);
129             weak = s;
130             assert(!weak.expired());
131         }
132         assert(weak.expired());
133         weak.reset();
134 
135 #ifndef TEST_HAS_NO_EXCEPTIONS
136         try {
137             TEST_IGNORE_NODISCARD ptr->shared_from_this();
138             assert(false);
139         } catch (std::bad_weak_ptr const&) {
140         } catch (...) { assert(false); }
141 #endif
142         {
143             std::shared_ptr<T> s2(ptr, &nullDeleter);
144             assert(ptr->shared_from_this() == s2);
145         }
146         delete ptr;
147         assert(globalMemCounter.checkOutstandingNewEq(0));
148     }
149     // Test weak_from_this_methods
150 #if TEST_STD_VER > 14
151     {
152         T* ptr = new T;
153         const T* cptr = ptr;
154 
155         static_assert(noexcept(ptr->weak_from_this()), "Operation must be noexcept");
156         static_assert(noexcept(cptr->weak_from_this()), "Operation must be noexcept");
157 
158         std::weak_ptr<T> my_weak = ptr->weak_from_this();
159         assert(my_weak.expired());
160 
161         std::weak_ptr<T const> my_const_weak = cptr->weak_from_this();
162         assert(my_const_weak.expired());
163 
164         // Enable shared_from_this with ptr.
165         std::shared_ptr<T> sptr(ptr);
166         my_weak = ptr->weak_from_this();
167         assert(!my_weak.expired());
168         assert(my_weak.lock().get() == ptr);
169     }
170 #endif
171 }
172