This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.
Section: 32.6.5.4.2 [thread.lock.unique.cons], 32.6.5.5.2 [thread.lock.shared.cons] Status: New Submitter: Casey Carter Opened: 2024-11-13 Last modified: 2024-11-18
Priority: Not Prioritized
View all other issues in [thread.lock.unique.cons].
View all issues with New status.
Discussion:
The postconditions in 32.6.5.4.2 [thread.lock.unique.cons] paragraph 19:
Postconditions:contradict themselves ifpm == u_p.pm
andowns == u_p.owns
(whereu_p
is the state ofu
just prior to this construction),u.pm == 0
andu.owns == false
.
*this
and the parameter u
refer to the same object.
(Presumably "this construction" means the assignment, and it is copy-pasta from
the move constructor postconditions.) Apparently
unique_lock
didn't get the memo that we require well-defined behavior
from self-move-assignment as of LWG 2839(i).
Also, the move assignment operator doesn't specify what it returns.
[2024-11-18; Casey expands the PR to cover shared_lock
]
shared_lock
has the same problems, and can be fixed in the same way.
Proposed resolution:
This wording is relative to N4993.
Drafting Note: I've chosen to use the move-into-temporary-and-swap idiom here to keep things short and sweet. Since move construction, swap, and destruction are allnoexcept
, I've promoted move assignment from "Throws: Nothing" tonoexcept
as well. This is consistent with eliminating the implicit narrow contract condition that*this
andu
refer to distinct objects.
In the class synopsis in 32.6.5.4.1 [thread.lock.unique.general],
annotate the move assignment operator as noexcept
:
namespace std { template<class Mutex> class unique_lock { [...] unique_lock& operator=(unique_lock&& u) noexcept; [...] }; }
Modify 32.6.5.4.2 [thread.lock.unique.cons] as follows:
unique_lock& operator=(unique_lock&& u) noexcept;
-18- Effects:
IfEquivalent to:owns
callspm->unlock()
.unique_lock{std::move(u)}.swap(*this)
.-?- Returns:
*this
.
-19- Postconditions:pm == u_p.pm
andowns == u_p.owns
(whereu_p
is the state ofu
just prior to this construction),u.pm == 0
andu.owns == false
.
-20- [Note 1: With a recursive mutex it is possible for both*this
and u to own the same mutex before the assignment. In this case, *this will own the mutex after the assignment and u will not. — end note]
-21- Throws: Nothing.
Modify 32.6.5.5.2 [thread.lock.shared.cons] as follows:
shared_lock& operator=(shared_lock&& sl) noexcept;
-17- Effects:
IfEquivalent to:owns
callspm->unlock_shared()
.shared_lock{std::move(sl)}.swap(*this)
.-?- Returns:
*this
.
-18- Postconditions:pm == sl_p.pm
andowns == sl_p.owns
(wheresl_p
is the state ofsl
just prior to this assignment),sl.pm == nullptr
andsl.owns == false
.