1 //===----------------------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 // template<class T>
10 // class enable_shared_from_this
11 // {
12 // protected:
13 //     enable_shared_from_this();
14 //     enable_shared_from_this(enable_shared_from_this const&);
15 //     enable_shared_from_this& operator=(enable_shared_from_this const&);
16 //     ~enable_shared_from_this();
17 // public:
18 //     shared_ptr<T> shared_from_this();
19 //     shared_ptr<T const> shared_from_this() const;
20 //     weak_ptr<T> weak_from_this() noexcept;                         // C++17
21 //     weak_ptr<T const> weak_from_this() const noexcept;             // C++17
22 // };
23 
24 #include <memory>
25 #include <cassert>
26 
27 #include "test_macros.h"
28 #include "count_new.h"
29 
30 struct T
31     : public std::enable_shared_from_this<T>
32 {
33 };
34 
35 struct Y : T {};
36 
37 struct Z : Y {};
38 
nullDeleter(void *)39 void nullDeleter(void*) {}
40 
41 struct Foo : virtual public std::enable_shared_from_this<Foo>
42 {
~FooFoo43     virtual ~Foo() {}
44 };
45 
46 struct Bar : public Foo {
BarBar47     Bar(int) {}
48 };
49 
50 
51 struct PrivateBase : private std::enable_shared_from_this<PrivateBase> {
52 };
53 
54 
main(int,char **)55 int main(int, char**)
56 {
57     globalMemCounter.reset();
58     {  // https://llvm.org/PR18843
59     std::shared_ptr<T const> t1(new T);
60     std::shared_ptr<T const> t2(std::make_shared<T>());
61     }
62     { // https://llvm.org/PR27115
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   return 0;
173 }
174