Created on 2017-07-07.00:00:00 last changed 46 months ago
Proposed resolution:
This wording is relative to N4750.
Edit [memory.syn], header <memory> synopsis, as indicated:
[…]
// [util.smartptr.shared.cast], shared_ptr casts
template<class T, class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r) noexcept;
template<class T, class U>
shared_ptr<T> static_pointer_cast(shared_ptr<U>&& r) noexcept;
template<class T, class U>
shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r) noexcept;
template<class T, class U>
shared_ptr<T> dynamic_pointer_cast(shared_ptr<U>&& r) noexcept;
template<class T, class U>
shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r) noexcept;
template<class T, class U>
shared_ptr<T> const_pointer_cast(shared_ptr<U>&& r) noexcept;
template<class T, class U>
shared_ptr<T> reinterpret_pointer_cast(const shared_ptr<U>& r) noexcept;
template<class T, class U>
shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U>&& r) noexcept;
[…]
Edit [util.smartptr.shared], class template shared_ptr synopsis, as indicated:
template<class T> class shared_ptr {
public:
[…]
// [util.smartptr.shared.const], constructors
[…]
template <class D, class A> shared_ptr(nullptr_t p, D d, A a);
template<class Y> shared_ptr(const shared_ptr<Y>& r, element_type* p) noexcept;
template<class Y> shared_ptr(shared_ptr<Y>&& r, element_type* p) noexcept;
shared_ptr(const shared_ptr& r) noexcept;
[…]
};
[…]
Edit [util.smartptr.shared.const] as indicated:
[Drafting note: the use_count() postcondition can safely be deleted because it is redundant with the "shares ownership" wording in the Effects. — end drafting note]
template<class Y> shared_ptr(const shared_ptr<Y>& r, element_type* p) noexcept; template<class Y> shared_ptr(shared_ptr<Y>&& r, element_type* p) noexcept;-14- Effects: Constructs a shared_ptr instance that stores p and shares ownership with the initial value of r.
-15- Postconditions: get() == p&& use_count() == r.use_count(). For the second overload, r is empty and r.get() == nullptr. -16- [Note: To avoid the possibility of a dangling pointer, the user of this constructor must ensure that p remains valid at least until the ownership group of r is destroyed. — end note] -17- [Note: This constructor allows creation of an empty shared_ptr instance with a non-null stored pointer. — end note]
Edit [util.smartptr.shared.cast] as indicated:
template<class T, class U> shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U>&& r) noexcept;-1- Requires: The expression static_cast<T*>((U*)nullptr) shall be well-formed.
-2- Returns:shared_ptr<T>(, where R is r for the first overload, and std::move(r) for the second. -3- [Note: The seemingly equivalent expression shared_ptr<T>(static_cast<T*>(r.get())) will eventually result in undefined behavior, attempting to delete the same object twice. — end note]rR, static_cast<typename shared_ptr<T>::element_type*>(r.get()))template<class T, class U> shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> dynamic_pointer_cast(shared_ptr<U>&& r) noexcept;-4- Requires: The expression dynamic_cast<T*>((U*)nullptr) shall be well-formed. The expression dynamic_cast<typename shared_ptr<T>::element_type*>(r.get()) shall be well formed and shall have well-defined behavior.
-5- Returns:
(5.1) — When dynamic_cast<typename shared_ptr<T>::element_type*>(r.get()) returns a non-null value p, shared_ptr<T>(
rR, p), where R is r for the first overload, and std::move(r) for the second.(5.2) — Otherwise, shared_ptr<T>().
-6- [Note: The seemingly equivalent expression shared_ptr<T>(dynamic_cast<T*>(r.get())) will eventually result in undefined behavior, attempting to delete the same object twice. — end note]
template<class T, class U> shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> const_pointer_cast(shared_ptr<U>&& r) noexcept;-7- Requires: The expression const_cast<T*>((U*)nullptr) shall be well-formed.
-8- Returns:shared_ptr<T>(, where R is r for the first overload, and std::move(r) for the second. -9- [Note: The seemingly equivalent expression shared_ptr<T>(const_cast<T*>(r.get())) will eventually result in undefined behavior, attempting to delete the same object twice. — end note]rR, const_cast<typename shared_ptr<T>::element_type*>(r.get()))template<class T, class U> shared_ptr<T> reinterpret_pointer_cast(const shared_ptr<U>& r) noexcept; template<class T, class U> shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U>&& r) noexcept;-10- Requires: The expression reinterpret_cast<T*>((U*)nullptr) shall be well-formed.
-11- Returns:shared_ptr<T>(, where R is r for the first overload, and std::move(r) for the second. -12- [Note: The seemingly equivalent expression shared_ptr<T>(reinterpret_cast<T*>(r.get())) will eventually result in undefined behavior, attempting to delete the same object twice. — end note]rR, reinterpret_cast<typename shared_ptr<T>::element_type*>(r.get()))
[ 2018-11, Adopted in San Diego ]
[ 2018-06 Rapperswil Monday AM ]
Move to Ready; choosing the PR in the issue as opposed to P0390R0 and rebase wording to most recent working draft
[ 2017-07 Toronto Tuesday PM issue prioritization ]
Status LEWG
The shared_ptr aliasing constructor and the shared_ptr casts are specified to take a shared_ptr by const reference and construct a new shared_ptr that shares ownership with it, and yet they have no corresponding rvalue reference overloads. That results in an unnecessary refcount increment/decrement when those operations are given an rvalue. Rvalue overloads can't be added as a conforming extension because they observably change semantics (but mostly only for code that does unreasonable things like pass an argument by move and then rely on the fact that it's unchanged), and [res.on.arguments]/p1.3 doesn't help because it only applies to rvalue reference parameters.
This issue is related to P0390R0.History | |||
---|---|---|---|
Date | User | Action | Args |
2021-02-25 10:48:01 | admin | set | status: wp -> c++20 |
2018-11-12 04:39:29 | admin | set | messages: + msg10185 |
2018-11-12 04:39:29 | admin | set | status: voting -> wp |
2018-10-08 05:13:59 | admin | set | status: ready -> voting |
2018-06-04 18:30:10 | admin | set | messages: + msg9861 |
2018-06-04 18:30:10 | admin | set | status: lewg -> ready |
2017-07-12 01:58:24 | admin | set | messages: + msg9359 |
2017-07-12 01:58:24 | admin | set | status: new -> lewg |
2017-07-08 12:58:20 | admin | set | messages: + msg9324 |
2017-07-07 00:00:00 | admin | create |