Movatterモバイル変換


[0]ホーム

URL:



This page is a snapshot from the LWG issues list, see theLibrary Active Issues List for more information and the meaning ofC++14 status.

2104.unique_lock move-assignment should not benoexcept

Section: 32.6.5.4[thread.lock.unique]Status:C++14Submitter: Anthony WilliamsOpened: 2011-11-27Last modified: 2017-07-05

Priority:Not Prioritized

View all issues withC++14 status.

Discussion:

I just noticed that theunique_lock move-assignment operator is declarednoexcept. This function may callunlock() on the wrapped mutex, which may throw.

Suggested change: remove thenoexcept specification fromunique_lock::operator=(unique_lock&&) in 32.6.5.4[thread.lock.unique] and 32.6.5.4.2[thread.lock.unique.cons].

Daniel:

I think the situation is actually a bit more complex as it initially looks.

First, the effects of the move-assignment operator are (emphasize mine):

Effects:Ifowns callspm->unlock().

Now according to theBasicLockable requirements:

m.unlock()

3Requires: The current execution agent shall hold a lock onm.

4Effects: Releases a lock onm held by the current execution agent.

Throws: Nothing.

This shows that unlock itself is a function with narrow contract and for this reasons no unlock function of a mutex or lock itself does have a noexcept specifier according to our mental model.

Now the move-assignment operatorattempts to satisfy theserequirement of the function and calls it only when it assumes that the conditions are ok, so from the view-point of the caller of the move-assignment operator it looks as if the move-assignment operator would in total a function with awide contract.

The problem with this analysis so far is, that it depends on the assumed correctness of the state "owns".

Looking at the construction or state-changing functions, there do exist several ones that depend on caller-code satisfying the requirements and there is one guy, who looks most suspicious:

unique_lock(mutex_type& m, adopt_lock_t);

11Requires: The calling thread own the mutex.
[…]
13Postconditions:pm == &m andowns == true.

because this function does not even calllock() (which may, but is not required to throw an exception if the calling thread does already own the mutex). So we have in fact still a move-assignment operator that might throw an exception, if the mutex was either constructed or used (call of lock) incorrectly.

The correct fix seems to me to also add a "Throws: Nothing" element tothe move-assignment operator, because using it correctly shall not throw anexception.

[Issaquah 2014-02-11: Move to Immediate after SG1 review]

Proposed resolution:

This wording is relative to the FDIS.

  1. Change 32.6.5.4[thread.lock.unique], class templateunique_lock synopsis as indicated:

    namespace std {  template <class Mutex>  class unique_lock {  public:    typedef Mutex mutex_type;    […]    unique_lock(unique_lock&& u) noexcept;    unique_lock& operator=(unique_lock&& u)noexcept;    […]  };}
  2. Change 32.6.5.4.2[thread.lock.unique.cons] around p22 as indicated:

    unique_lock& operator=(unique_lock&& u)noexcept;

    -22-Effects: Ifowns callspm->unlock().

    -23-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.

    -24- [Note: With a recursive mutex it is possible for both*this andu to own the same mutex before the assignment. In this case,*this will own the mutex after the assignment andu will not. —end note]

    -??-Throws: Nothing.


[8]ページ先頭

©2009-2026 Movatter.jp