Home | History | Annotate | Download | only in util.smartptr.enab
      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 
     40 void nullDeleter(void*) {}
     41 
     42 struct Foo : virtual public std::enable_shared_from_this<Foo>
     43 {
     44     virtual ~Foo() {}
     45 };
     46 
     47 struct Bar : public Foo {
     48     Bar(int) {}
     49 };
     50 
     51 
     52 struct PrivateBase : private std::enable_shared_from_this<PrivateBase> {
     53 };
     54 
     55 
     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