Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 44 additions & 11 deletions stl/inc/memory
Original file line number Diff line number Diff line change
Expand Up @@ -794,6 +794,40 @@ protected:
}
}

template <class _Ty2>
void _Weakly_convert_lvalue_avoiding_expired_conversions(const _Ptr_base<_Ty2>& _Other) noexcept {
// implement weak_ptr's copy converting ctor
if (_Other._Rep) {
_Rep = _Other._Rep; // always share ownership
_Rep->_Incwref();

if (_Rep->_Incref_nz()) {
_Ptr = _Other._Ptr; // keep resource alive during conversion, handling virtual inheritance
_Rep->_Decref();
} else {
_STL_INTERNAL_CHECK(!_Ptr);
}
} else {
_STL_INTERNAL_CHECK(!_Ptr && !_Rep);
}
}

template <class _Ty2>
void _Weakly_convert_rvalue_avoiding_expired_conversions(_Ptr_base<_Ty2>&& _Other) noexcept {
// implement weak_ptr's move converting ctor
_Rep = _Other._Rep; // always transfer ownership
_Other._Rep = nullptr;

if (_Rep && _Rep->_Incref_nz()) {
_Ptr = _Other._Ptr; // keep resource alive during conversion, handling virtual inheritance
_Rep->_Decref();
} else {
_STL_INTERNAL_CHECK(!_Ptr);
}

_Other._Ptr = nullptr;
}

void _Incwref() const noexcept {
if (_Rep) {
_Rep->_Incwref();
Expand Down Expand Up @@ -2255,30 +2289,29 @@ _NODISCARD enable_if_t<is_bounded_array_v<_Ty>, shared_ptr<_Ty>> allocate_shared
template <class _Ty>
class weak_ptr : public _Ptr_base<_Ty> { // class for pointer to reference counted resource
public:
constexpr weak_ptr() noexcept {} // construct empty weak_ptr object
constexpr weak_ptr() noexcept {}

weak_ptr(const weak_ptr& _Other) noexcept { // construct weak_ptr object for resource pointed to by _Other
this->_Weakly_construct_from(_Other);
weak_ptr(const weak_ptr& _Other) noexcept {
this->_Weakly_construct_from(_Other); // same type, no conversion
}

template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr(const shared_ptr<_Ty2>& _Other) noexcept { // construct weak_ptr object for resource owned by _Other
this->_Weakly_construct_from(_Other);
weak_ptr(const shared_ptr<_Ty2>& _Other) noexcept {
this->_Weakly_construct_from(_Other); // shared_ptr keeps resource alive during conversion
}

template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr(const weak_ptr<_Ty2>& _Other) noexcept { // construct weak_ptr object for resource pointed to by _Other
this->_Weakly_construct_from(_Other.lock());
weak_ptr(const weak_ptr<_Ty2>& _Other) noexcept {
this->_Weakly_convert_lvalue_avoiding_expired_conversions(_Other);
}

weak_ptr(weak_ptr&& _Other) noexcept { // move construct from _Other
weak_ptr(weak_ptr&& _Other) noexcept {
this->_Move_construct_from(_STD move(_Other));
}

template <class _Ty2, enable_if_t<_SP_pointer_compatible<_Ty2, _Ty>::value, int> = 0>
weak_ptr(weak_ptr<_Ty2>&& _Other) noexcept { // move construct from _Other
this->_Weakly_construct_from(_Other.lock());
_Other.reset();
weak_ptr(weak_ptr<_Ty2>&& _Other) noexcept {
this->_Weakly_convert_rvalue_avoiding_expired_conversions(_STD move(_Other));
}

~weak_ptr() noexcept {
Expand Down
4 changes: 2 additions & 2 deletions stl/inc/tuple
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ _INLINE_VAR constexpr bool _Tuple_nothrow_assignable_v =
_Tuple_nothrow_assignable_v0<tuple_size_v<_Dest> == sizeof...(_Srcs), _Dest, _Srcs...>;

// STRUCT TEMPLATE _Tuple_convert_copy_val
// Constrain tuple's converting copy constructor (LWG-2549)
// Constrain tuple's copy converting constructor (LWG-2549)
template <class _Myself, class... _Other>
struct _Tuple_convert_copy_val : true_type {};

Expand All @@ -125,7 +125,7 @@ struct _Tuple_convert_copy_val<tuple<_This>, _Uty>
is_convertible<const tuple<_Uty>&, _This>>> {};

// STRUCT TEMPLATE _Tuple_convert_move_val
// Constrain tuple's converting move constructor (LWG-2549)
// Constrain tuple's move converting constructor (LWG-2549)
template <class _Myself, class... _Other>
struct _Tuple_convert_move_val : true_type {};

Expand Down
97 changes: 79 additions & 18 deletions tests/std/tests/Dev10_851347_weak_ptr_virtual_inheritance/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,109 @@
#include <assert.h>
#include <memory>
#include <utility>

using namespace std;

// Also test GH-1102 "<memory>: weak_ptr conversions don't preserve control blocks for expired objects"
template <typename T, typename U>
[[nodiscard]] bool owner_equal(const weak_ptr<T>& t, const weak_ptr<U>& u) {
return !t.owner_before(u) && !u.owner_before(t);
}

void test_owner_equal() {
shared_ptr<int> sp_alive1(new int(0));
shared_ptr<int> sp_alive2(new int(0));
shared_ptr<int> sp_expiring3(new int(0));
shared_ptr<int> sp_expiring4(new int(0));

weak_ptr<int> wp_empty;
weak_ptr<int> wp_also_empty;

weak_ptr<int> wp_alive(sp_alive1);
weak_ptr<int> wp_alive_same(sp_alive1);
weak_ptr<int> wp_alive_different(sp_alive2);

weak_ptr<int> wp_expired(sp_expiring3);
weak_ptr<int> wp_expired_same(sp_expiring3);
weak_ptr<int> wp_expired_different(sp_expiring4);

sp_expiring3.reset();
sp_expiring4.reset();

assert(wp_empty.expired());
assert(wp_also_empty.expired());

assert(!wp_alive.expired());
assert(!wp_alive_same.expired());
assert(!wp_alive_different.expired());

assert(wp_expired.expired());
assert(wp_expired_same.expired());
assert(wp_expired_different.expired());

assert(owner_equal(wp_empty, wp_also_empty));

assert(!owner_equal(wp_empty, wp_alive));
assert(!owner_equal(wp_empty, wp_expired));

assert(!owner_equal(wp_alive, wp_empty));
assert(!owner_equal(wp_expired, wp_empty));

assert(owner_equal(wp_alive, wp_alive_same));
assert(owner_equal(wp_expired, wp_expired_same));

assert(!owner_equal(wp_alive, wp_alive_different));
assert(!owner_equal(wp_alive, wp_expired));
assert(!owner_equal(wp_expired, wp_alive));
assert(!owner_equal(wp_expired, wp_expired_different));
}

struct A {
int a;
int a{10};
};

struct B : virtual public A {
int b;
struct B : virtual A {
int b{20};
};

struct C : virtual public A {
int c;
struct C : virtual A {
int c{30};
};

struct D : public B, public C {
int d;
struct D : B, C {
int d{40};
};

int main() {
test_owner_equal();

shared_ptr<D> spd(new D);

weak_ptr<D> wpd(spd);
weak_ptr<D> wpd2(spd);
const weak_ptr<D> wpd_zero(spd);
weak_ptr<D> wpd_one(spd);
weak_ptr<D> wpd_two(spd);

spd.reset();
weak_ptr<A> wpa0(wpd_zero);
assert(!wpa0.expired());
assert(owner_equal(wpa0, wpd_zero));
assert(wpa0.lock()->a == 10);

weak_ptr<A> wpa1(wpd);
spd.reset();

weak_ptr<A> wpa1(wpd_one);
assert(wpa1.expired());
assert(owner_equal(wpa1, wpd_zero));

weak_ptr<A> wpa2;

wpa2 = wpd;

wpa2 = wpd_one;
assert(wpa2.expired());
assert(owner_equal(wpa2, wpd_zero));


weak_ptr<A> wpa3(move(wpd));
weak_ptr<A> wpa3(move(wpd_one));
assert(wpa3.expired());
assert(owner_equal(wpa3, wpd_zero));

weak_ptr<A> wpa4;
wpa4 = move(wpd2);
wpa4 = move(wpd_two);
assert(wpa4.expired());
assert(owner_equal(wpa4, wpd_zero));
}
2 changes: 1 addition & 1 deletion tests/std/tests/P0414R2_shared_ptr_for_arrays/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -939,7 +939,7 @@ void test_LWG_2996() {
assert(sp1.use_count() == 1);
assert(sp1.get() == pz);

shared_ptr<const BaseX> sp2(move(sp1)); // converting move ctor, old
shared_ptr<const BaseX> sp2(move(sp1)); // move converting ctor, old
assert(sp1.use_count() == 0);
assert(sp1.get() == nullptr);
assert(sp2.use_count() == 1);
Expand Down