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
30struct T
31 : public std::enable_shared_from_this<T>
32{
33};
34
35struct Y : T {};
36
37struct Z : Y {};
38
39void nullDeleter(void*) {}
40
41struct Foo : virtual public std::enable_shared_from_this<Foo>
42{
43 virtual ~Foo() {}
44};
45
46struct Bar : public Foo {
47 Bar(int) {}
48};
49
50
51struct PrivateBase : private std::enable_shared_from_this<PrivateBase> {
52};
53
54
55int 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>(args&: 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

source code of libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.enab/enable_shared_from_this.pass.cpp