1 /*
2  * Copyright 2013-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <memory>
20 
21 namespace folly {
22 
23 /*
24  * folly::enable_shared_from_this
25  *
26  * To be removed once C++17 becomes a minimum requirement for folly.
27  */
28 #if __cplusplus >= 201700L || __cpp_lib_enable_shared_from_this >= 201603L
29 
30 // Guaranteed to have std::enable_shared_from_this::weak_from_this(). Prefer
31 // type alias over our own class.
32 /* using override */ using std::enable_shared_from_this;
33 
34 #else
35 
36 /**
37  * Extends std::enabled_shared_from_this. Offers weak_from_this() to pre-C++17
38  * code. Use as drop-in replacement for std::enable_shared_from_this.
39  *
40  * C++14 has no direct means of creating a std::weak_ptr, one must always
41  * create a (temporary) std::shared_ptr first. C++17 adds weak_from_this() to
42  * std::enable_shared_from_this to avoid that overhead. Alas code that must
43  * compile under different language versions cannot call
44  * std::enable_shared_from_this::weak_from_this() directly. Hence this class.
45  *
46  * @example
47  *   class MyClass : public folly::enable_shared_from_this<MyClass> {};
48  *
49  *   int main() {
50  *     std::shared_ptr<MyClass> sp = std::make_shared<MyClass>();
51  *     std::weak_ptr<MyClass> wp = sp->weak_from_this();
52  *   }
53  */
54 template <typename T>
55 class enable_shared_from_this : public std::enable_shared_from_this<T> {
56  public:
57   constexpr enable_shared_from_this() noexcept = default;
58 
59   std::weak_ptr<T> weak_from_this() noexcept {
60     return weak_from_this_<T>(this);
61   }
62 
63   std::weak_ptr<T const> weak_from_this() const noexcept {
64     return weak_from_this_<T>(this);
65   }
66 
67  private:
68   // Uses SFINAE to detect and call
69   // std::enable_shared_from_this<T>::weak_from_this() if available. Falls
70   // back to std::enable_shared_from_this<T>::shared_from_this() otherwise.
71   template <typename U>
72   auto weak_from_this_(std::enable_shared_from_this<U>* base_ptr) noexcept
73       -> decltype(base_ptr->weak_from_this()) {
74     return base_ptr->weak_from_this();
75   }
76 
77   template <typename U>
78   auto weak_from_this_(std::enable_shared_from_this<U> const* base_ptr) const
79       noexcept -> decltype(base_ptr->weak_from_this()) {
80     return base_ptr->weak_from_this();
81   }
82 
83   template <typename U>
84   std::weak_ptr<U> weak_from_this_(...) noexcept {
85     try {
86       return this->shared_from_this();
87     } catch (std::bad_weak_ptr const&) {
88       // C++17 requires that weak_from_this() on an object not owned by a
89       // shared_ptr returns an empty weak_ptr. Sadly, in C++14,
90       // shared_from_this() on such an object is undefined behavior, and there
91       // is nothing we can do to detect and handle the situation in a portable
92       // manner. But in case a compiler is nice enough to implement C++17
93       // semantics of shared_from_this() and throws a bad_weak_ptr, we catch it
94       // and return an empty weak_ptr.
95       return std::weak_ptr<U>{};
96     }
97   }
98 
99   template <typename U>
100   std::weak_ptr<U const> weak_from_this_(...) const noexcept {
101     try {
102       return this->shared_from_this();
103     } catch (std::bad_weak_ptr const&) {
104       return std::weak_ptr<U const>{};
105     }
106   }
107 };
108 
109 #endif
110 
111 } // namespace folly
112