Skip to content

Commit ef62730

Browse files
authored
Enable STL-style enable_shared_from_this (#1295)
1 parent 6397999 commit ef62730

File tree

2 files changed

+96
-4
lines changed

2 files changed

+96
-4
lines changed

ctl/shared_ptr.h

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#define CTL_SHARED_PTR_H_
55

66
#include "exception.h"
7+
#include "is_base_of.h"
78
#include "is_convertible.h"
89
#include "remove_extent.h"
910
#include "unique_ptr.h"
@@ -201,10 +202,7 @@ class shared_ptr
201202

202203
template<typename U, typename D>
203204
requires __::shared_ptr_compatible<T, U>
204-
shared_ptr(U* const p, D d)
205-
: p(p), rc(__::shared_pointer<U, D>::make(p, move(d)))
206-
{
207-
}
205+
shared_ptr(U*, D);
208206

209207
template<typename U>
210208
shared_ptr(const shared_ptr<U>& r, element_type* p) noexcept
@@ -443,6 +441,62 @@ class weak_ptr
443441
__::shared_ref* rc = nullptr;
444442
};
445443

444+
template<typename T>
445+
class enable_shared_from_this
446+
{
447+
public:
448+
shared_ptr<T> shared_from_this()
449+
{
450+
return shared_ptr<T>(weak_this);
451+
}
452+
shared_ptr<T const> shared_from_this() const
453+
{
454+
return shared_ptr<T>(weak_this);
455+
}
456+
457+
weak_ptr<T> weak_from_this()
458+
{
459+
return weak_this;
460+
}
461+
weak_ptr<T const> weak_from_this() const
462+
{
463+
return weak_this;
464+
}
465+
466+
protected:
467+
constexpr enable_shared_from_this() noexcept = default;
468+
enable_shared_from_this(const enable_shared_from_this& r) noexcept
469+
{
470+
}
471+
~enable_shared_from_this() = default;
472+
473+
enable_shared_from_this& operator=(
474+
const enable_shared_from_this& r) noexcept
475+
{
476+
return *this;
477+
}
478+
479+
private:
480+
template<typename U, typename... Args>
481+
friend shared_ptr<U> make_shared(Args&&...);
482+
483+
template<typename U>
484+
friend class shared_ptr;
485+
486+
weak_ptr<T> weak_this;
487+
};
488+
489+
template<typename T>
490+
template<typename U, typename D>
491+
requires __::shared_ptr_compatible<T, U>
492+
shared_ptr<T>::shared_ptr(U* const p, D d)
493+
: p(p), rc(__::shared_pointer<U, D>::make(p, move(d)))
494+
{
495+
if constexpr (is_base_of_v<enable_shared_from_this<U>, U>) {
496+
p->weak_this = *this;
497+
}
498+
}
499+
446500
template<typename T, typename... Args>
447501
shared_ptr<T>
448502
make_shared(Args&&... args)
@@ -452,6 +506,9 @@ make_shared(Args&&... args)
452506
shared_ptr<T> r;
453507
r.p = &rc->t;
454508
r.rc = rc.release();
509+
if constexpr (is_base_of_v<enable_shared_from_this<T>, T>) {
510+
r->weak_this = r;
511+
}
455512
return r;
456513
}
457514

test/ctl/shared_ptr_test.cc

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
// #define ctl std
2626

2727
using ctl::bad_weak_ptr;
28+
using ctl::enable_shared_from_this;
2829
using ctl::make_shared;
2930
using ctl::move;
3031
using ctl::shared_ptr;
@@ -66,6 +67,27 @@ struct Base
6667
struct Derived : Base
6768
{};
6869

70+
class SharedThis : public enable_shared_from_this<SharedThis>
71+
{
72+
struct Private
73+
{
74+
explicit Private() = default;
75+
};
76+
77+
public:
78+
SharedThis(Private)
79+
{
80+
}
81+
82+
static shared_ptr<SharedThis> create()
83+
{
84+
return make_shared<SharedThis>(Private());
85+
}
86+
};
87+
88+
class CanShareThis : public enable_shared_from_this<CanShareThis>
89+
{};
90+
6991
int
7092
main()
7193
{
@@ -241,6 +263,19 @@ main()
241263
return 23;
242264
}
243265

266+
{
267+
// enable_shared_from_this allows shared pointers to self.
268+
auto x = SharedThis::create();
269+
auto y = x->shared_from_this();
270+
if (x.use_count() != 2 || x.get() != y.get())
271+
return 24;
272+
auto z = new CanShareThis();
273+
auto w = shared_ptr<CanShareThis>(z);
274+
auto v = w->shared_from_this();
275+
if (w.use_count() != 2 || w.get() != v.get())
276+
return 25;
277+
}
278+
244279
// TODO(mrdomino): exercise threads / races. The reference count should be
245280
// atomically maintained.
246281

0 commit comments

Comments
 (0)