Doc. no. | N3245=11-0015 |
Date: | 2011-02-28 |
Project: | Programming Language C++ |
Reply to: | Alisdair Meredith <lwgchair@gmail.com> |
Revised 2011-02-28 at 12:02:47 UTC
Reference ISO/IEC IS 14882:2003(E)
Also see:
The purpose of this document is to record the status of issues which have come before the Library Working Group (LWG) of the INCITS PL22.16 and ISO WG21 C++ Standards Committee. Issues represent potential defects in the ISO/IEC IS 14882:2003(E) document.
This document contains only library issues which are actively being considered by the Library Working Group, i.e., issues which have a status of New, Open, Ready, or Review. See Library Defect Reports List for issues considered defects and Library Closed Issues List for issues considered closed.
The issues in these lists are not necessarily formal ISO Defect Reports (DR's). While some issues will eventually be elevated to official Defect Report status, other issues will be disposed of in other ways. See Issue Status.
Prior to Revision 14, library issues lists existed in two slightly different versions; a Committee Version and a Public Version. Beginning with Revision 14 the two versions were combined into a single version.
This document includes [bracketed italicized notes] as a reminder to the LWG of current progress on issues. Such notes are strictly unofficial and should be read with caution as they may be incomplete or incorrect. Be aware that LWG support for a particular resolution can quickly change if new viewpoints or killer examples are presented in subsequent discussions.
For the most current official version of this document see http://www.open-std.org/jtc1/sc22/wg21/. Requests for further information about this document should include the document number above, reference ISO/IEC 14882:2003(E), and be submitted to Information Technology Industry Council (ITI), 1250 Eye Street NW, Washington, DC 20005.
Public information as to how to obtain a copy of the C++ Standard, join the standards committee, submit an issue, or comment on an issue can be found in the comp.std.c++ FAQ.
New - The issue has not yet been reviewed by the LWG. Any Proposed Resolution is purely a suggestion from the issue submitter, and should not be construed as the view of LWG.
Open - The LWG has discussed the issue but is not yet ready to move the issue forward. There are several possible reasons for open status:
A Proposed Resolution for an open issue is still not be construed as the view of LWG. Comments on the current state of discussions are often given at the end of open issues in an italic font. Such comments are for information only and should not be given undue importance.
Deferred - The LWG has discussed the issue, is not yet ready to move the issue forward, but neither does it deem the issue significant enough to delay publishing a standard or Technical Report. A typical deferred issue would be seeking to clarify wording that might be technically correct, but easily mis-read.
A Proposed Resolution for a deferred issue is still not be construed as the view of LWG. Comments on the current state of discussions are often given at the end of open issues in an italic font. Such comments are for information only and should not be given undue importance.
Dup - The LWG has reached consensus that the issue is a duplicate of another issue, and will not be further dealt with. A Rationale identifies the duplicated issue's issue number.
NAD - The LWG has reached consensus that the issue is not a defect in the Standard.
NAD Editorial - The LWG has reached consensus that the issue can either be handled editorially, or is handled by a paper (usually linked to in the rationale).
NAD Concepts - The LWG has reached consensus that the issue is NAD for now, but represents a real issue when the library is done with language-supported concepts.
NAD Future - In addition to the regular status, the LWG believes that this issue should be revisited at the next revision of the standard.
Review - Exact wording of a Proposed Resolution is now available for review on an issue for which the LWG previously reached informal consensus.
Ready - The LWG has reached consensus that the issue is a defect in the Standard, the Proposed Resolution is correct, and the issue is ready to forward to the full committee for further action as a Defect Report (DR).
Resolved - The LWG has reached consensus that the issue is a defect in the Standard, but the resolution adopted to resolve the issue came via some other mechanism than this issue in the list - typically by applying a formal paper, occasionally as a side effect of consolidating several interacting issue resolutions into a single issue.
DR - (Defect Report) - The full WG21/PL22.16 committee has voted to forward the issue to the Project Editor to be processed as a Potential Defect Report. The Project Editor reviews the issue, and then forwards it to the WG21 Convenor, who returns it to the full committee for final disposition. This issues list accords the status of DR to all these Defect Reports regardless of where they are in that process.
TC1 - (Technical Corrigenda 1) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution as a Technical Corrigenda. Action on this issue is thus complete and no further action is possible under ISO rules.
CD1 - (Committee Draft 2008) - The full WG21/PL22.16 committee has voted to accept the Defect Report's Proposed Resolution into the Fall 2008 Committee Draft.
TRDec - (Decimal TR defect) - The LWG has voted to accept the Defect Report's Proposed Resolution into the Decimal TR. Action on this issue is thus complete and no further action is expected.
WP - (Working Paper) - The proposed resolution has not been accepted as a Technical Corrigendum, but the full WG21/PL22.16 committee has voted to apply the Defect Report's Proposed Resolution to the working paper.
Tentatively - This is a status qualifier. The issue has been reviewed online, or at an unofficial meeting, but not in an official meeting, and some support has been formed for the qualified status. Tentatively qualified issues may be moved to the unqualified status and forwarded to full committee (if Ready) within the same meeting. Unlike Ready issues, Tentatively Ready issues will be reviewed in subcommittee prior to forwarding to full committee. When a status is qualified with Tentatively, the issue is still considered active.
Pending - This is a status qualifier. When prepended to a status this indicates the issue has been processed by the committee, and a decision has been made to move the issue to the associated unqualified status. However for logistical reasons the indicated outcome of the issue has not yet appeared in the latest working paper.
Issues are always given the status of New when they first appear on the issues list. They may progress to Open or Review while the LWG is actively working on them. When the LWG has reached consensus on the disposition of an issue, the status will then change to Dup, NAD, or Ready as appropriate. Once the full J16 committee votes to forward Ready issues to the Project Editor, they are given the status of Defect Report ( DR). These in turn may become the basis for Technical Corrigenda (TC), or are closed without action other than a Record of Response (RR ). The intent of this LWG process is that only issues which are truly defects in the Standard move to the formal ISO DR status.
Section: 30.5.2 [thread.condition.condvarany] Status: Open Submitter: Pete Becker Opened: 2009-01-07 Last modified: 2011-02-21
View all other issues in [thread.condition.condvarany].
View all issues with Open status.
Discussion:
The requirements for the constructor for condition_variable has several error conditions, but the requirements for the constructor for condition_variable_any has none. Is this difference intentional?
[ Summit: ]
Move to open, pass to Howard. If this is intentional, a note may be helpful. If the error conditions are to be copied from condition_variable, this depends on LWG 965.
[ Post Summit Howard adds: ]
The original intention (N2447) was to let the OS return whatever errors it was going to return, and for those to be translated into exceptions, for both condition_variable and condition_variable_any. I have not received any complaints about specific error conditions from vendors on non-POSIX platforms, but such complaints would not surprise me if they surfaced.
[ 2009-10 Santa Cruz: ]
Leave open. Benjamin to provide wording.
[ 2010 Pittsburgh: ]
We don't have throw clauses for condition variables.
This issue may be dependent on LWG 1268.
Leave open. Detlef will coordinate with Benjamin.
Consider merging LWG 964, 966, and 1268 into a single paper.
Proposed resolution:
Section: 30.5.1 [thread.condition.condvar] Status: Open Submitter: Pete Becker Opened: 2009-01-07 Last modified: 2011-02-21
View all other issues in [thread.condition.condvar].
View all issues with Open status.
Discussion:
30.5.1 [thread.condition.condvar]: condition_variable::wait and condition_variable::wait_until both have a postcondition that lock is locked by the calling thread, and a throws clause that requires throwing an exception if this postcondition cannot be achieved. How can the implementation detect that this lock can never be obtained?
[ Summit: ]
Move to open. Requires wording. Agreed this is an issue, and the specification should not require detecting deadlocks.
[ 2009-08-01 Howard provides wording. ]
The proposed wording is inspired by the POSIX spec which says:
- [EINVAL]
- The value specified by cond or mutex is invalid.
- [EPERM]
- The mutex was not owned by the current thread at the time of the call.
I do not believe [EINVAL] is possible without memory corruption (which we don't specify). [EPERM] is possible if this thread doesn't own the mutex, which is listed as a precondition. "May" is used instead of "Shall" because not all OS's are POSIX.
[ 2009-10 Santa Cruz: ]
Leave open, Detlef to provide improved wording.
[ 2009-10-23 Detlef Provided wording. ]
Detlef's wording put in Proposed resolution. Original wording here:
Change 30.5.1 [thread.condition.condvar] p12, p19 and 30.5.2 [thread.condition.condvarany] p10, p16:
Throws: May throw std::system_error if a precondition is not met.
when the effects or postcondition cannot be achieved.
[ 2009-10 Santa Cruz: ]
Leave open, Detlef to provide improved wording.
[ 2009-11-18 Anthony adds: ]
condition_variable::wait takes a unique_lock<mutex>. We know whether or not a unique_lock owns a lock, through use of its owns_lock() member.
I would like to propose the following resolution:
Modify the first sentence of 30.5.1 [thread.condition.condvar] p9:
void wait(unique_lock<mutex>& lock);9 Precondition:
lock is locked by the calling threadlock.owns_lock() is true, and either...
Replace 30.5.1 [thread.condition.condvar] p11-13 with:
void wait(unique_lock<mutex>& lock);...
11 Postcondition:
lock is locked by the calling threadlock.owns_lock() is true.12 Throws: std::system_error
when the effects or postcondition cannot be achievedif the implementation detects that the preconditions are not met or the effects cannot be achieved. Any exception thrown by lock.lock() or lock.unlock().13 Error Conditions: The error conditions are implementation defined.
equivalent error condition from lock.lock() or lock.unlock().
[ 2010 Pittsburgh: ]
There are heavy conflicts with adopted papers.
This issue is dependent on LWG 1268.
Leave open pending outstanding edits to the working draft. Detlef will provide wording.
Possibly related to 964.
Proposed resolution:
Replace 30.5.1 [thread.condition.condvar] p12, p19 and 30.5.2 [thread.condition.condvarany] p10, p16:
Throws: std::system_error when the effects or postcondition cannot be achieved.
Error conditions:
equivalent error condition from lock.lock() or lock.unlock().Throws: It is implementation-defined whether a std::system_error with implementation-defined error condition is thrown if the precondition is not met.
Section: 23.2.1 [container.requirements.general] Status: Open Submitter: Rani Sharoni Opened: 2009-02-12 Last modified: 2011-02-21
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with Open status.
Discussion:
Introduction
This proposal is meant to resolve potential regression of the N2800 draft, see next section, and to relax the requirements for containers of types with throwing move constructors.
The basic problem is that some containers operations, like push_back, have a strong exception safety guarantee (i.e. no side effects upon exception) that are not achievable when throwing move constructors are used since there is no way to guarantee revert after partial move. For such operations the implementation can at most provide the basic guarantee (i.e. valid but unpredictable) as it does with multi copying operations (e.g. range insert).
For example, vector<T>::push_back() (where T has a move constructor) might resize the vector and move the objects to the new underlying buffer. If move constructor throws it might not be possible to recover the throwing object or to move the old objects back to the original buffer.
The current draft is explicit by disallowing throwing move for some operations (e.g. vector<>::reserve) and not clear about other operations mentioned in 23.2.1 [container.requirements.general]/10 (e.g. single element insert): it guarantees strong exception safety without explicitly disallowing a throwing move constructor.
Regression
This section only refers to cases in which the contained object is by itself a standard container.
Move constructors of standard containers are allowed to throw and therefore existing operations are broken, compared with C++03, due to move optimization. (In fact existing implementations like Dinkumware are actually throwing).
For example, vector< list<int> >::reserve yields undefined behavior since list<int>'s move constructor is allowed to throw. On the other hand, the same operation has strong exception safety guarantee in C++03.
There are few options to solve this regression:
Option 1 is suggested by proposal N2815 but it might not be applicable for existing implementations for which containers default constructors are throwing.
Option 2 limits the usage significantly and it's error prone by allowing zombie objects that are nothing but destructible (e.g. no clear() is allowed after move). It also potentially complicates the implementation by introducing special state.
Option 3 is possible, for example, using default construction and swap instead of move for standard containers case. The implementation is also free to provide special hidden operation for non throwing move without forcing the user the cope with the limitation of option-2 when using the public move.
Option 4 impact the efficiency in all use cases due to rare throwing move.
The proposed wording will imply option 1 or 3 though option 2 is also achievable using more wording. I personally oppose to option 2 that has impact on usability.
Relaxation for user types
Disallowing throwing move constructors in general seems very restrictive since, for example, common implementation of move will be default construction + swap so move will throw if the default constructor will throw. This is currently the case with the Dinkumware implementation of node based containers (e.g. std::list) though this section doesn't refer to standard types.
For throwing move constructors it seem that the implementation should have no problems to provide the basic guarantee instead of the strong one. It's better to allow throwing move constructors with basic guarantee than to disallow it silently (compile and run), via undefined behavior.
There might still be cases in which the relaxation will break existing generic code that assumes the strong guarantee but it's broken either way given a throwing move constructor since this is not a preserving optimization.
[ Batavia (2009-05): ]
Bjarne comments (referring to his draft paper): "I believe that my suggestion simply solves that. Thus, we don't need a throwing move."
Move to Open and recommend it be deferred until after the next Committee Draft is issued.
[ 2009-10 Santa Cruz: ]
Should wait to get direction from Dave/Rani (N2983).
[ 2010-03-28 Daniel updated wording to sync with N3092. ]
The suggested change of 23.3.3.4 [deque.modifiers]/2 should be removed, because the current wording does say more general things:
2 Remarks: If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of T there are no effects. If an exception is thrown by the move constructor of a non-CopyConstructible T, the effects are unspecified.
The suggested change of 23.3.6.3 [vector.capacity]/2 should be removed, because the current wording does say more general things:
2 Effects: A directive that informs a vector of a planned change in size, so that it can manage the storage allocation accordingly. After reserve(), capacity() is greater or equal to the argument of reserve if reallocation happens; and equal to the previous value of capacity() otherwise. Reallocation happens at this point if and only if the current capacity is less than the argument of reserve(). If an exception is thrown other than by the move constructor of a non-CopyConstructible type, there are no effects.
Proposed resolution:
23.2.1 [container.requirements.general] paragraph 11 add footnote:
-11- Unless otherwise specified (see 23.1.4.1, 23.1.5.1, 23.2.2.3, and 23.2.6.4) all container types defined in this Clause meet the following additional requirements:
- ...
[Note: for compatibility with C++ 2003, when "no effect" is required, standard containers should not use the value_type's throwing move constructor when the contained object is by itself a standard container. -- end note]
23.2.5.1 [unord.req.except] change paragraph 2 to say:
-2- For unordered associative containers, if an exception is thrown by any operation other than the container's hash function from within an insert() function inserting a single element, the insert() function has no effect unless the exception is thrown by the contained object move constructor.
-4- For unordered associative containers, if an exception is thrown from within a rehash() function other than by the container's hash function or comparison function, the rehash() function has no effect unless the exception is thrown by the contained object move constructor.
23.3.3.4 [deque.modifiers] change paragraph 2 to say:
-2- Remarks: If an exception is thrown other than by the copy constructor, move constructor or assignment operator of T there are no effects. If an exception is thrown by push_back() or emplace_back() function, that function has no effects unless the exception is thrown by the move constructor of T.
23.3.6.3 [vector.capacity] paragraph 2 change to say:
-2- Effects: A directive that informs a vector of a planned change in size, so that it can manage the storage allocation accordingly. After reserve(), capacity() is greater or equal to the argument of reserve if reallocation happens; and equal to the previous value of capacity() otherwise. Reallocation happens at this point if and only if the current capacity is less than the argument of reserve(). If an exception is thrown, there are no effects unless the exception is thrown by the contained object move constructor.
23.3.6.3 [vector.capacity] paragraph 12 change to say:
-12- Requires:
If value_type has a move constructor, that constructor shall not throw any exceptions.If an exception is thrown, there are no effects unless the exception is thrown by the contained object move constructor.
23.3.6.5 [vector.modifiers] change paragraph 1 to say:
-1-
Requires: If value_type has a move constructor, that constructor shall not throw any exceptions.Remarks: If an exception is thrown by push_back() or emplace_back() function, that function has no effect unless the exception is thrown by the move constructor of T.
Section: 22.4.2.1.2 [facet.num.get.virtuals] Status: Open Submitter: Cosmin Truta Opened: 2009-07-04 Last modified: 2011-02-21
View all other issues in [facet.num.get.virtuals].
View all issues with Open status.
Discussion:
As specified in the latest draft,
N2914,
num_get
is still not fully compatible with the following C
functions: strtoul
, strtoull
,
strtof
and
strtod
.
In C, when conversion of a string to an unsigned integer type falls
outside the
representable range, strtoul
and strtoull
return
ULONG_MAX
and ULLONG_MAX
, respectively,
regardless
whether the input field represents a positive or a negative value.
On the other hand, the result of num_get
conversion of
negative
values to unsigned integer types is zero. This raises a compatibility
issue.
Moreover, in C, when conversion of a string to a floating-point type falls
outside the representable range, strtof
, strtod
and
strtold
return ±HUGE_VALF
,
±HUGE_VAL
and ±HUGE_VALL
, respectively.
On the other hand, the result of num_get
conversion of such
out-of-range floating-point values results in the most positive/negative
representable value.
Although many C library implementations do implement HUGE_VAL
(etc.) as the highest representable (which is, usually, the infinity),
this isn't required by the C standard. The C library specification makes no
statement regarding the value of HUGE_VAL
and friends, which
potentially raises the same compatibility issue as in the above case of
unsigned integers.
In addition, neither C nor C++ define symbolic constants for the maximum
representable floating-point values (they only do so only for the maximum
representable finite floating-point values), which raises a
usability
issue (it would be hard for the programmer to check the result of
num_get
against overflow).
As such, we propose to adjust the specification of num_get
to
closely follow the behavior of all of its underlying C functions.
[ 2010 Rapperswil: ]
Some concern that this is changing the specification for an existing C++03 function, but it was pointed out that this was underspecified as resolved by issue 23. This is clean-up for that issue in turn. Some concern that we are trying to solve the same problem in both clause 22 and 27.
Bill: There's a change here as to whether val is stored to in an error case.
Pablo: Don't think this changes whether val is stored to or not, but changes the value that is stored.
Bill: Remembers having skirmishes with customers and testers as to whether val is stored to, and the resolution was not to store in error cases.
Howard: Believes since C++03 we made a change to always store in overflow.
Everyone took some time to review the issue.
Pablo: C++98 definitely did not store any value during an error condition.
Dietmar: Depends on the question of what is considered an error, and whether overflow is an error or not, which was the crux of LWG 23.
Pablo: Yes, but given the "zero, if the conversion function fails to convert the entire field", we are requiring every error condition to store.
Bill: When did this happen?
Alisdair: One of the last two or three meetings.
Dietmar: To store a value in case of failure is a very bad idea.
Move to Open, needs more study.
Proposed resolution:
Change 22.4.2.1.2 [facet.num.get.virtuals] as follows:
Stage 3: The sequence of
char
s accumulated in stage 2 (the field) is converted to a numeric value by the rules of one of the functions declared in the header<cstdlib>
:
- For a signed integer value, the function
strtoll
.- For an unsigned integer value, the function
strtoull
.- For a
float
value, the functionstrtof
.- For a
double
value, the functionstrtod
.- For a
floating-pointlong double
value, the functionstrtold
.The numeric value to be stored can be one of:
- zero, if the conversion function fails to convert the entire field.
ios_base::failbit
is assigned toerr
.- the most positive (or negative) representable value, if the field to be converted to a signed integer type represents a value too large positive (or negative) to be represented in
val
.ios_base::failbit
is assigned toerr
.the most negative representable value or zero for an unsigned integer type, if the field represents a value too large negative to be represented inval
.ios_base::failbit
is assigned toerr
.- the most positive representable value, if the field to be converted to an unsigned integer type represents a value that cannot be represented in
val
.- the converted value, otherwise.
The resultant numeric value is stored in
val
. If the conversion function fails to convert the entire field, or if the field represents a value outside the range of representable values,ios_base::failbit
is assigned toerr
.
Section: 23.2.5 [unord.req] Status: Open Submitter: Pablo Halpern Opened: 2009-07-17 Last modified: 2011-02-28
View other active issues in [unord.req].
View all other issues in [unord.req].
View all issues with Open status.
Discussion:
When I look at the unordered_* constructors, I think the complexity is poorly described and does not follow the style of the rest of the standard.
The complexity for the default constructor is specified as constant. Actually, it is proportional to n, but there are no invocations of value_type constructors or other value_type operations.
For the iterator-based constructor the complexity should be:
Complexity: exactly n calls to construct value_type from InputIterator::value_type (where n = distance(f,l)). The number of calls to key_equal::operator() is proportional to n in the average case and n*n in the worst case.
[ 2010 Rapperswil: ]
Concern that the current wording may require O(1) where that cannot be delivered. We need to look at both the clause 23 requirements tables and the constructor description of each unordered container to be sure.
Howard suggests NAD Editorial as we updated the container requirement tables since this issue was written.
Daniel offers to look deeper, and hopefully produce wording addressing any outstanding concerns at the next meeting.
Move to Open.
[2011-02-26: Daniel provides wording]
I strongly suggest to clean-up the differences between requirement tables and individual specifications. In the usual way, the most specific specifications wins, which is in this case the wrong one. In regard to the concern expressed about missing DefaultConstructible requirements of the value type I disagree: The function argument n is no size-control parameter, but only some effective capacity parameter: No elements will be value-initialized by these constructors. The necessary requirement for the value type, EmplaceConstructible into *this, is already listed in Table 103 — Unordered associative container requirements. Another part of the proposed resolution is the fact that there is an inconsistency of the complexity counting when both a range and a bucket count is involved compared to constructions where only bucket counts are provided: E.g. the construction X a(n); has a complexity of n bucket allocations, but this part of the work is omitted for X a(i, j, n);, even though it is considerable larger (in the average case) for n ≫ distance(i, j).
Proposed resolution:
Modify the following rows in Table 103 — Unordered associative container requirements to add the explicit bucket allocation overhead of some constructions. As editorial recommendation it is suggested not to shorten the sum 𝒪(n) + 𝒪(N) to 𝒪(n + N), because two different work units are involved.
Table 103 — Unordered associative container requirements (in addition to container) Expression Return type Assertion⁄note pre-⁄post-condition Complexity … X(i, j, n, hf, eq)
X a(i, j, n, hf, eq)X …
Effects: Constructs an empty container with at least n
buckets, using hf as the hash function and eq as the key
equality predicate, and inserts elements from [i, j) into it.Average case 𝒪(n) + 𝒪(N) (N is distance(i, j)),
worst case 𝒪(n) + 𝒪(N2)X(i, j, n, hf)
X a(i, j, n, hf)X …
Effects: Constructs an empty container with at least n
buckets, using hf as the hash function and key_equal() as the key
equality predicate, and inserts elements from [i, j) into it.Average case 𝒪(n) + 𝒪(N) (N is distance(i, j)),
worst case 𝒪(n) + 𝒪(N2)X(i, j, n)
X a(i, j, n)X …
Effects: Constructs an empty container with at least n
buckets, using hasher() as the hash function and key_equal() as the key
equality predicate, and inserts elements from [i, j) into it.Average case 𝒪(n) + 𝒪(N) (N is distance(i, j)),
worst case 𝒪(n) + 𝒪(N2)…
Modify 23.5.4.2 [unord.map.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):
explicit unordered_map(size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());1 Effects: Constructs an empty unordered_map using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is implementation-defined
impldefdefault number of buckets in unordered_map. max_load_factor() returns 1.0.2 Complexity: Constant if n is not provided, otherwise linear in n to construct the buckets.
template <class InputIterator> unordered_map(InputIterator f, InputIterator l, size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());3 Effects: Constructs an empty unordered_map using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is implementation-defined
impldefdefault number of buckets in unordered_map. Then inserts elements from the range [f, l). max_load_factor() returns 1.0.4 Complexity:
Average case linear, worst case quadraticConstant if n is not provided, else linear in n to construct the buckets. In the average case linear in N and in the worst case quadratic in N to insert the elements, where N is equal to distance(f, l).
Modify 23.5.5.2 [unord.multimap.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):
explicit unordered_multimap(size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());1 Effects: Constructs an empty unordered_multimap using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is implementation-defined
impldefdefault number of buckets in unordered_multimap. max_load_factor() returns 1.0.2 Complexity: Constant if n is not provided, otherwise linear in n to construct the buckets.
template <class InputIterator> unordered_multimap(InputIterator f, InputIterator l, size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());3 Effects: Constructs an empty unordered_multimap using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is implementation-defined
impldefdefault number of buckets in unordered_multimap. Then inserts elements from the range [f, l). max_load_factor() returns 1.0.4 Complexity:
Average case linear, worst case quadraticConstant if n is not provided, else linear in n to construct the buckets. In the average case linear in N and in the worst case quadratic in N to insert the elements, where N is equal to distance(f, l).
Modify 23.5.6.2 [unord.set.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):
explicit unordered_set(size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());1 Effects: Constructs an empty unordered_set using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is implementation-defined
impldefdefault number of buckets in unordered_set. max_load_factor() returns 1.0.2 Complexity: Constant if n is not provided, otherwise linear in n to construct the buckets.
template <class InputIterator> unordered_set(InputIterator f, InputIterator l, size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());3 Effects: Constructs an empty unordered_set using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is implementation-defined
impldefdefault number of buckets in unordered_set. Then inserts elements from the range [f, l). max_load_factor() returns 1.0.4 Complexity:
Average case linear, worst case quadraticConstant if n is not provided, else linear in n to construct the buckets. In the average case linear in N and in the worst case quadratic in N to insert the elements, where N is equal to distance(f, l).
Modify 23.5.7.2 [unord.multiset.cnstr] p. 1-4 as indicated (The edits of p. 1 and p. 3 attempt to fix some editorial oversight.):
explicit unordered_multiset(size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());1 Effects: Constructs an empty unordered_multiset using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is implementation-defined
impldefdefault number of buckets in unordered_multiset. max_load_factor() returns 1.0.2 Complexity: Constant if n is not provided, otherwise linear in n to construct the buckets.
template <class InputIterator> unordered_multiset(InputIterator f, InputIterator l, size_type n = see below, const hasher& hf = hasher(), const key_equal& eql = key_equal(), const allocator_type& a = allocator_type());3 Effects: Constructs an empty unordered_multiset using the specified hash function, key equality function, and allocator, and using at least n buckets. If n is not provided, the number of buckets is implementation-defined
impldefdefault number of buckets in unordered_multiset. Then inserts elements from the range [f, l). max_load_factor() returns 1.0.4 Complexity:
Average case linear, worst case quadraticConstant if n is not provided, else linear in n to construct the buckets. In the average case linear in N and in the worst case quadratic in N to insert the elements, where N is equal to distance(f, l).
Section: 24.2 [iterator.requirements] Status: Deferred Submitter: Daniel Krügler Opened: 2009-09-19 Last modified: 2011-02-21
View all other issues in [iterator.requirements].
View all issues with Deferred status.
Discussion:
The terms valid iterator and singular aren't properly defined. The fuzziness of those terms became even worse after the resolution of 208 (including further updates by 278). In 24.2 [iterator.requirements] as of N2723 the standard says now:
5 - These values are called past-the-end values. Values of an iterator i for which the expression *i is defined are called dereferenceable. The library never assumes that past-the-end values are dereferenceable. Iterators can also have singular values that are not associated with any container. [...] Results of most expressions are undefined for singular values; the only exceptions are destroying an iterator that holds a singular value and the assignment of a non-singular value to an iterator that holds a singular value. [...] Dereferenceable values are always non-singular.
10 - An invalid iterator is an iterator that may be singular.
First, issue 208 intentionally removed the earlier constraint that past-the-end values are always non-singular. The reason for this was to support null pointers as past-the-end iterators of e.g. empty sequences. But there seem to exist different views on what a singular (iterator) value is. E.g. according to the SGI definition a null pointer is not a singular value:
Dereferenceable iterators are always nonsingular, but the converse is not true. For example, a null pointer is nonsingular (there are well defined operations involving null pointers) even thought it is not dereferenceable.
and proceeds:
An iterator is valid if it is dereferenceable or past-the-end.
Even if the standard prefers a different meaning of singular here, the change was incomplete, because by restricting feasible expressions of singular iterators to destruction and assignment isn't sufficient for a past-the-end iterator: Of-course it must still be equality-comparable and in general be a readable value.
Second, the standard doesn't clearly say whether a past-the-end value is a valid iterator or not. E.g. 20.6.12 [specialized.algorithms]/1 says:
In all of the following algorithms, the formal template parameter ForwardIterator is required to satisfy the requirements of a forward iterator (24.1.3) [..], and is required to have the property that no exceptions are thrown from [..], or dereference of valid iterators.
The standard should make better clear what "singular pointer" and "valid iterator" means. The fact that the meaning of a valid value has a core language meaning doesn't imply that for an iterator concept the term "valid iterator" has the same meaning.
Let me add a final example: In X [allocator.concepts.members] of N2914 we find:
pointer X::allocate(size_type n);11 Returns: a pointer to the allocated memory. [Note: if n == 0, the return value is unspecified. —end note]
[..]
void X::deallocate(pointer p, size_type n);Preconditions: p shall be a non-singular pointer value obtained from a call to allocate() on this allocator or one that compares equal to it.
If singular pointer value would include null pointers this make the preconditions unclear if the pointer value is a result of allocate(0): Since the return value is unspecified, it could be a null pointer. Does that mean that programmers need to check the pointer value for a null value before calling deallocate?
[ 2010-11-09 Daniel comments: ]
A later paper is in preparation.
[ 2010 Batavia: ]
Doesn't need to be resolved for Ox
Proposed resolution:
Consider to await the paper.
Section: 23.2.4 [associative.reqmts] Status: Deferred Submitter: Daniel Krügler Opened: 2009-09-20 Last modified: 2011-02-21
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with Deferred status.
Discussion:
Scott Meyers' mentions on a recent posting on c.s.c++ some arguments that point to an incomplete resolution of 103 and to an inconsistency of requirements on keys in ordered and unordered associative containers:
1) 103 introduced the term immutable without defining it in a unique manner in 23.2.4 [associative.reqmts]/5:
[..] Keys in an associative container are immutable.
According to conventional dictionaries immutable is an unconditional way of saying that something cannot be changed. So without any further explicit allowance a user always runs into undefined behavior if (s)he attempts to modify such a key. IMO this was not the intend of the committee to resolve 103 in that way because the comments suggest an interpretation that should give any user the freedom to modify the key in an explicit way provided it would not affect the sort order in that container.
2) Another observation was that surprisingly no similar 'safety guards' exists against unintentional key changes for the unordered associative containers, specifically there is no such requirement as in 23.2.4 [associative.reqmts]/6 that "both iterator and const_iterator are constant iterators". But the need for such protection against unintentional changes as well as the constraints in which manner any explicit changes may be performed are both missing and necessary, because such changes could potentially change the equivalence of keys that is measured by the hasher and key_equal.
I suggest to fix the unconditional wording involved with "immutable keys" by at least adding a hint for the reader that users may perform such changes in an explicit manner and to perform similar wording changes as 103 did for the ordered associative containers also for the unordered containers.
[ 2010-03-27 Daniel provides wording. ]
This update attempts to provide normative wording that harmonizes the key and function object constraints of associative and unordered containers.
[ 2010 Batavia: ]
We're uncomfortable with the first agenda item, and we can live with the second agenda item being applied before or after Madrid.
Proposed resolution:
Change 23.2.4 [associative.reqmts]/2 as indicated: [This ensures that associative containers make better clear what this "arbitrary" type is, as the unordered containers do in 23.2.5 [unord.req]/3]
2 Each associative container is parameterized on Key and an ordering relation Compare that induces a strict weak ordering (25.4) on elements of Key. In addition, map and multimap associate an arbitrary mapped type
typeT with the Key. The object of type Compare is called the comparison object of a container.
Change 23.2.4 [associative.reqmts]/5 as indicated: [This removes the too strong requirement that keys must not be changed at all and brings this line in sync with 23.2.5 [unord.req]/7. We take care about the real constraints by the remaining suggested changes. The rationale provided by LWG 103 didn't really argue why that addition is necessary, and I believe the remaining additions make it clear that any user changes have strong restrictions]:
5 For set and multiset the value type is the same as the key type. For map and multimap it is equal to pair<const Key, T>.
Keys in an associative container are immutable.
Change 23.2.5 [unord.req]/3+4 as indicated: [The current sentence of p.4 has doesn't say something really new and this whole subclause misses to define the concepts of the container-specific hasher object and predicate object. We introduce the term key equality predicate which is already used in the requirements table. This change does not really correct part of this issue, but is recommended to better clarify the nomenclature and the difference between the function objects and the function object types, which is important, because both can potentially be stateful.]
3 Each unordered associative container is parameterized by Key, by a function object type Hash that meets the Hash requirements (20.2.4) and acts as a hash function for argument values of type Key, and by a binary predicate Pred that induces an equivalence relation on values of type Key. Additionally, unordered_map and unordered_multimap associate an arbitrary mapped type T with the Key.
4 The container's object of type Hash - denoted by hash - is called the hash function of the container. The container's object of type Pred - denoted by pred - is called the key equality predicate of the container.
A hash function is a function object that takes a single argument of type Key and returns a value of type std::size_t.
Change 23.2.5 [unord.req]/5 as indicated: [This adds a similar safe-guard as the last sentence of 23.2.4 [associative.reqmts]/3]
5 Two values k1 and k2 of type Key are considered equivalent if the container's key equality predicate
key_equal function objectreturns true when passed those values. If k1 and k2 are equivalent, the container's hash function shall return the same value for both. [Note: thus, when an unordered associative container is instantiated with a non-default Pred parameter it usually needs a non-default Hash parameter as well. — end note] For any two keys k1 and k2 in the same container, calling pred(k1, k2) shall always return the same value. For any key k in a container, calling hash(k) shall always return the same value.
After 23.2.5 [unord.req]/7 add the following new paragraph: [This ensures the same level of compile-time protection that we already require for associative containers. It is necessary for similar reasons, because any change in the stored key which would change it's equality relation to others or would change it's hash value such that it would no longer fall in the same bucket, would break the container invariants]
7 For unordered_set and unordered_multiset the value type is the same as the key type. For unordered_map and unordered_multimap it is std::pair<const Key, T>.
For unordered containers where the value type is the same as the key type, both iterator and const_iterator are constant iterators. It is unspecified whether or not iterator and const_iterator are the same type. [Note: iterator and const_iterator have identical semantics in this case, and iterator is convertible to const_iterator. Users can avoid violating the One Definition Rule by always using const_iterator in their function parameter lists. — end note]
Section: 23.3.5.5 [list.ops] Status: Tentatively Ready Submitter: Pablo Halpern Opened: 2009-09-24 Last modified: 2010-11-13
View all other issues in [list.ops].
View all issues with Tentatively Ready status.
Discussion:
In Bellevue (I think), we passed N2525, which, among other things, specifies that the behavior of list::splice is undefined if the allocators of the two lists being spliced do not compare equal. The same rationale should apply to list::merge. The intent of list::merge (AFAIK) is to move nodes from one sorted list into another sorted list without copying the elements. This is possible only if the allocators compare equal.
Proposed resolution:
Relative to the August 2009 WP, N2857, change 23.3.5.5 [list.ops], paragraphs 22-25 as follows:
void merge(list&& x); template <class Compare> void merge(list&& x, Compare comp);Requires: both the list and the argument list shall be sorted according to operator< or comp.
Effects: If (&x == this) does nothing; otherwise, merges the two sorted ranges [begin(), end()) and [x.begin(), x.end()). The result is a range in which the elements will be sorted in non-decreasing order according to the ordering defined by comp; that is, for every iterator i, in the range other than the first, the condition comp(*i, *(i - 1)) will be false.
Remarks: Stable. If (&x != this) the range [x.begin(), x.end()) is empty after the merge. No elements are copied by this operation. The behavior is undefined if this->get_allocator() != x.get_allocator().
Complexity: At most size() + x.size() - 1 applications of comp if (&x != this); otherwise, no applications of comp are performed. If an exception is thrown other than by a comparison there are no effects.
Section: 22.3.3.2.3 [conversions.buffer] Status: Open Submitter: Bo Persson Opened: 2009-10-21 Last modified: 2011-02-21
View all issues with Open status.
Discussion:
The synopisis for wbuffer_convert 22.3.3.2.3 [conversions.buffer]/2 contains
typedef typename Tr::state_type state_type;
making state_type a synonym for (possibly) some char_traits<x>::state_type.
However, in paragraph 9 of the same section, we have
typedef typename Codecvt::state_type state_type;The type shall be a synonym for Codecvt::state_type.
From what I can see, it might be hard to implement wbuffer_convert if the types were not both std::mbstate_t, but I cannot find a requirement that they must be the same type.
[ Batavia 2010: ]
Howard to draft wording, move to Review. Run it by Bill. Need to move this in Madrid.
Proposed resolution:
Section: 23.2.4 [associative.reqmts] Status: Tentatively Ready Submitter: Boris Dušek Opened: 2009-10-24 Last modified: 2011-02-24
View other active issues in [associative.reqmts].
View all other issues in [associative.reqmts].
View all issues with Tentatively Ready status.
Discussion:
In the latest published draft N2960, section 23.2.4 [associative.reqmts], paragraph 8, it is specified that that insert does not invalidate any iterators. As per 23.2.1 [container.requirements.general], paragraph 12, this holds true not only for insert, but emplace as well. This gives the insert member a special treatment w.r.t. emplace member in 23.2.4 [associative.reqmts], par. 8, since both modify the container. For the sake of consistency, in 23.2.4 [associative.reqmts], par. 8: either reference to insert should be removed (i.e. count on 23.2.1 [container.requirements.general], par. 12), or reference to emplace be added (i.e. mention all members of assoc. containers that modify it).
[ 2009-11-18 Chris provided wording. ]
This suggested wording covers both the issue discussed, and a number of other identical issues (namely insert being discussed without emplace). I'm happy to go back and split and introduce a new issue if appropriate, but I think the changes are fairly mechanical and obvious.
[ 2010-01-23 Daniel Krügler and J. Daniel García updated wording to make the use of hint consistent with insert. ]
[ 2011-02-23 Daniel Krügler adapts wording to numbering changes to match the N3225 draft. During this action it was found that 23.2.5 [unord.req] had been changed considerably due to acceptance of N3068 during the Pittsburgh meeting, such that the suggested wording change to p. 6 can no longer be applied. The new wording is more general and should now include insert() and emplace() calls as well ("mutating operations"). ]
Proposed resolution:
Modify bullet 1 of 23.2.1 [container.requirements.general], p11:
11 Unless otherwise specified (see 23.2.4.1, 23.2.5.1, 23.3.2.3, and 23.3.5.4) all container types defined in this Clause meet the following additional requirements:
Modify 23.2.4 [associative.reqmts], p4:
4 An associative container supports unique keys if it may contain at most one element for each key. Otherwise, it supports equivalent keys. The set and map classes support unique keys; the multiset and multimap classes support equivalent keys. For multiset and multimap, insert, emplace, and erase preserve the relative ordering of equivalent elements.
Modify Table 102 — Associative container requirements in 23.2.4 [associative.reqmts]:
Table 102 — Associative container requirements (in addition to container) Expression Return type Assertion/note
pre-/post-conditionComplexity ... a_eq.emplace(args) iterator [..] Effects: Inserts a T object t constructed with std::forward<Args>(args)... and returns the iterator pointing to the newly inserted element. If a range containing elements equivalent to t exists in a_eq, t is inserted at the end of that range. logarithmic a.emplace_hint(p, args) iterator equivalent to a.emplace(std::forward<Args>(args)...). Return value is an iterator pointing to the element with the key equivalent to the newly inserted element. The const_iterator p is a hint pointing to where the search should start.The element is inserted as close as possible to the position just prior to p.Implementations are permitted to ignore the hint.logarithmic in general, but amortized constant if the element is inserted right afterbefore p...
Modify 23.2.4 [associative.reqmts], p9:
9 The insert and emplace members shall not affect the validity of iterators and references to the container, and the erase members shall invalidate only iterators and references to the erased elements.
Modify 23.2.4.1 [associative.reqmts.except], p2:
2 For associative containers, if an exception is thrown by any operation from within an insert() or emplace() function inserting a single element, the
insert() functioninsertion has no effect.
Modify 23.2.5 [unord.req], p13 and p14:
6 An unordered associative container supports unique keys if it may contain at most one element for each key. Otherwise, it supports equivalent keys. unordered_set and unordered_map support unique keys. unordered_multiset and unordered_multimap support equivalent keys. In containers that support equivalent keys, elements with equivalent keys are adjacent to each other in the iteration order of the container. Thus, although the absolute order of elements in an unordered container is not specified, its elements are grouped into equivalent-key groups such that all elements of each group have equivalent keys. Mutating operations on unordered containers shall preserve the relative order of elements within each equivalent-key group unless otherwise specified.
13 The insert and emplace members shall not affect the validity of references to container elements, but may invalidate all iterators to the container. The erase members shall invalidate only iterators and references to the erased elements.
14 The insert and emplace members shall not affect the validity of iterators if (N+n) < z * B, where N is the number of elements in the container prior to the insert operation, n is the number of elements inserted, B is the container's bucket count, and z is the container's maximum load factor.
Modify 23.2.5.1 [unord.req.except], p2:
2 For unordered associative containers, if an exception is thrown by any operation other than the container's hash function from within an insert() or emplace() function inserting a single element, the
insert()insertionfunctionhas no effect.
Section: D.10.1 [depr.base] Status: Ready Submitter: Alberto Ganesh Barbati Opened: 2009-11-30 Last modified: 2011-02-28
View all issues with Ready status.
Discussion:
A program should not be allowed to add specialization of class templates unary_function and binary_function, in force of 17.6.4.2.1 [namespace.std]/1. If a program were allowed to specialize these templates, the library could no longer rely on them to provide the intended typedefs or there might be other undesired interactions.
[ 2010-03-27 Daniel adds: ]
Accepting issue 1290 would resolve this issue as NAD editorial.
[ 2010-10-24 Daniel adds: ]
Accepting n3145 would resolve this issue as NAD editorial.
[ 2010 Batavia: Solved by N3198 ]
Previous proposed resolution:
Change paragraph X [base]/1 as follows:
1 The following
classesclass templates are provided to simplify the typedefs of the argument and result types:. A program shall not declare specializations of these templates.
Proposed resolution:
Addressed by paper D3198.
Section: 20.7.1.4 [unique.ptr.special] Status: Open Submitter: Daniel Krügler Opened: 2009-12-23 Last modified: 2011-02-21
View all issues with Open status.
Discussion:
The comparison functions of unique_ptr currently directly delegate to the underlying comparison functions of unique_ptr<T, D>::pointer. This is disadvantageous, because this would not guarantee to induce a total ordering for native pointers and it is hard to define a total order for mixed types anyway.
The currently suggested resolution for shared_ptr comparison as of 1262 uses a normalization strategy: They perform the comparison on the composite pointer type (5.9 [expr.rel]). This is not exactly possible for unique_ptr in the presence of user-defined pointer-like types but the existing definition of std::duration comparison as of 20.11.5.6 [time.duration.comparisons] via common_type of both argument types demonstrates a solution of this problem. The approach can be seen as the general way to define a composite pointer type and this is the approach which is used for here suggested wording change.
For consistency reasons I would have preferred the same normalization strategy for == and !=, but Howard convinced me not to do so (now).
[ 2010-11-03 Daniel comments and adjustes the currently proposed wording changes: ]
Issue 1401 is remotely related. Bullet A of its proposed resolution provides an alternative solution for issue discussed here and addresses NB comment GB-99. Additionally I updated the below suggested wording in regard to the following: It is an unncessary requirement that the below defined effective composite pointer-like type CT satisfies the LessThanComparable requirements. All what is needed is, that the function object type less<CT> induces a strict weak ordering on the pointer values.
Proposed resolution:
Change 20.7.1.4 [unique.ptr.special]/4-7 as indicated: [The implicit requirements and remarks imposed on the last three operators are the same as for the first one due to the normative "equivalent to" usage within a Requires element, see 17.5.1.4 [structure.specifications]/4. The effects of this change are that all real pointers wrapped in a unique_ptr will order like shared_ptr does.]
template <class T1, class D1, class T2, class D2> bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);? Requires: Let CT be common_type<unique_ptr<T1, D1>::pointer, unique_ptr<T2, D2>::pointer>::type. Then the specialization less<CT> shall be a function object type ([function.objects]) that induces a strict weak ordering ([alg.sorting]) on the pointer values.
4 Returns: less<CT>()(x.get(), y.get())
x.get() < y.get().? Remarks: If unique_ptr<T1, D1>::pointer is not implicitly convertible to CT or unique_ptr<T2, D2>::pointer is not implicitly convertible to CT, the program is ill-formed.
template <class T1, class D1, class T2, class D2> bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);5 Effects: Equivalent to return !(y < x)
Returns: x.get() <= y.get().template <class T1, class D1, class T2, class D2> bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);6 Effects: Equivalent to return (y < x)
Returns: x.get() > y.get().template <class T1, class D1, class T2, class D2> bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);7 Effects: Equivalent to return !(x < y)
Returns: x.get() >= y.get().
Section: 23.3.4.6 [forwardlist.ops] Status: Tentatively Ready Submitter: Howard Hinnant Opened: 2010-02-05 Last modified: 2010-11-13
View all other issues in [forwardlist.ops].
View all issues with Tentatively Ready status.
Discussion:
We've moved 1133 to Tentatively Ready and I'm fine with that.
1133 adds lvalue-references to the splice signatures for list. So now list can splice from lvalue and rvalue lists (which was the intent of the original move papers btw). During the discussion of this issue it was mentioned that if we want to give the same treatment to forward_list, that should be a separate issue.
This is that separate issue.
Consider the following case where you want to splice elements from one place in a forward_list to another. Currently this must be coded like so:
fl.splice_after(to_here, std::move(fl), from1, from2);
This looks pretty shocking to me. I would expect to be able to code instead:
fl.splice_after(to_here, fl, from1, from2);
but we currently don't allow it.
When I say move(fl), I consider that as saying that I don't care about the value of fl any more (until I assign it a new value). But in the above example, this simply isn't true. I do care about the value of fl after the move, and I'm not assigning it a new value. I'm merely permuting its current value.
I propose adding forward_list& overloads to the 3 splice_after members. For consistency's sake (principal of least surprise) I'm also proposing to overload merge this way as well.
Proposed resolution:
Add to the synopsis of 23.3.4 [forwardlist]:
template <class T, class Allocator = allocator<T> > class forward_list { public: ... void splice_after(const_iterator p, forward_list& x); void splice_after(const_iterator p, forward_list&& x); void splice_after(const_iterator p, forward_list& x, const_iterator i); void splice_after(const_iterator p, forward_list&& x, const_iterator i); void splice_after(const_iterator p, forward_list& x, const_iterator first, const_iterator last); void splice_after(const_iterator p, forward_list&& x, const_iterator first, const_iterator last); ... void merge(forward_list& x); void merge(forward_list&& x); template <class Compare> void merge(forward_list& x, Compare comp); template <class Compare> void merge(forward_list&& x, Compare comp); ... };
Add to the signatures of 23.3.4.6 [forwardlist.ops]:
void splice_after(const_iterator p, forward_list& x); void splice_after(const_iterator p, forward_list&& x);1 ...
void splice_after(const_iterator p, forward_list& x, const_iterator i); void splice_after(const_iterator p, forward_list&& x, const_iterator i);5 ...
void splice_after(const_iterator p, forward_list& x, const_iterator first, const_iterator last); void splice_after(const_iterator p, forward_list&& x, const_iterator first, const_iterator last);9 ...
void merge(forward_list& x); void merge(forward_list&& x); template <class Compare> void merge(forward_list& x, Compare comp); template <class Compare> void merge(forward_list&& x, Compare comp);18 ...
Section: 20.6.8.1 [allocator.traits.types] Status: Open Submitter: Pete Becker Opened: 2010-02-11 Last modified: 2011-02-28
View all issues with Open status.
Duplicate of: 1375
Discussion:
Addresses US-87
N2982 says that containers should have a nested typedef that defines their reference_type as value_type&; the previous standard deferred to the allocator to define its reference_type, and containers simply passed the allocator's typedef on. This change is a mistake. Allocators should define both a pointer type and a reference type. That's essential for their original purpose, which was to make different memory models transparent. If an allocator defines a pointer type that isn't compatible with a normal pointer it also has to define a corresponding reference type. For example (and please forgive a Windows-ism), if an allocator's pointer is T __far*, then it's reference has to be T __far&. Otherwise everything crashes (under the hood, references are pointers and have to have the same memory access mechanics). Extensions such as this for more general memory models were explicitly encouraged by C++03, and the allocator's pointer and reference typedefs were the hooks for such extensions. Removing the allocator's reference and const_reference typedefs makes those extensions unimplementable and breaks existing implementations that rely on those hooks.
[ 2010-02-25 Alisdair adds: ]
vector<bool>::reference is a nested class, and not a typedef. It should be removed from the list of containers when this change is made.
In general, I am uncomfortable placing this reference requirement on each container, as I would prefer to require:
is_same<Container::reference, Container::iterator::reference>This distinction is important, if we intend to support proxy iterators. The iterator paper in the pre-Pittsburgh mailing (N3046) does not make this proposal, but organises clause 24 in such a way this will be much easier to specify.
The changes to clause 20 remain important for all the reasons Pete highlights.
[ 2010 Batavia ]
Removed vector from list of templates that should be adjusted as of meeting outcome.
[ 2010 post-Batavia ]
Replaced vector<bool> reference by vector reference because of misinterpreting meeting typo. Additional corrected numbering in P/R to N3225 wording.
[ 2010-12-06 Daniel reopens ]
Unfortunately, the current P/R is defective for several reasons:
Especially the second and third items are misses in the 1318 P/R, e.g. in N2723 or in C++03 these were referring to X::reference and X::const_reference, resp. None of them is referenced anywhere in the allocator requirements table: r and s where historically needed to define the expressions a.address(r) and a.address(s) which are gone now, and t was needed to define the expression a.construct(p, t) which has been replaced by a.construct(p,args). The easiest fix seems to be to remove all three rows from Table 43.
t a value of type const T& r a value of type T& obtained by the expression *p s a value of type const T& obtained by the expression *q or by conversion from a value r
similar to the other container types, i.e. to define reference and const_reference now asstack priority_queue queue
This would not only be an ill-formed definition (because there is no name Allocator in scope), but it would also introduce a breakage compared to C++03, where these definitions where already referring to the definition of the wrapped containers. So, the adaptor class templates should be removed from the current list.typedef typename allocator_traits<Allocator>::reference reference; typedef typename allocator_traits<Allocator>::const_reference const_reference;
because it is an immutable container (And we had this definition already in N2723). The application of the rule would change this silently.typedef const_reference reference;
for the unordered containers they aretypedef typename allocator_traits<Allocator>::pointer pointer; typedef typename allocator_traits<Allocator>::const_pointer const_pointer;
These definitions are not equivalent, because allocators are no longer required to define typedefs pointer and const_pointer, the allocator_traits were invented as a further indirection to cope with that. I.e. for the unordered containers we need to bring both the definition of references and pointers in sync.typedef typename allocator_type::pointer pointer; typedef typename allocator_type::const_pointer const_pointer;
[ 2011-02-23 Daniel updates the proposed wording with support from Pablo ]
The update attempts to fix the backward-compatibility problem that we have introduced by ignoring the C++03 member function overloads address of allocator types in C++0x completely. The resolution attempts to fix that by adding these functions as optional members of allocators that are considered first before falling back to pointer_traits::pointer_to. This still allows us to remove the unused symbol t from the table, but we adapt the symbols r and s to purely refer to the typenames reference and const_reference.
Proposed resolution:
Edit the following three rows from Table 43:
Table 43 — Descriptive variable definitions Variable Definition ta value of type const T&... ... r a value of type T&XX::reference obtained by the expression *p.s a value of type const T&XX::const_reference obtained by the expression *q or by conversion from a value r.
Add the following rows to Table 44, Allocator requirements:
Table 44 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault ... ... ... ... X::reference T& X::const_reference X::reference is convertible to
X::const_referenceconst T& X::value_type Identical to T
Change the following two rows in Table 44:
Table 44 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault *p T&X::reference*q const T&X::const_reference*q refers to the same object as *p ... ... ... ... static_cast<X::pointer>(w) X::pointer static_cast<X::pointer>(w)
== pstatic_cast<X::const_pointer>(z) X::const_pointer static_cast<X::const_pointer>(z)
== qa.address(r) X::pointer a.address(r) == p pointer_traits<X::pointer>::pointer_to(r) a.address(s) X::const_pointer a.address(s) == q pointer_traits<X::const_pointer>::pointer_to(s)
Add the following typedef declarations to allocator_traits 20.6.8 [allocator.traits]:
template <class Alloc> struct allocator_traits { ... typedef see below void_pointer; typedef see below const_void_pointer; typedef see below reference; typedef see below const_reference; ... static pointer address(Alloc& a, reference r) noexcept; static const_pointer address(Alloc& a, const_reference r) noexcept; static pointer allocate(Alloc& a, size_type n); static pointer allocate(Alloc& a, size_type n, const_void_pointer hint); ...
Add the following descriptions to 20.6.8.1 [allocator.traits.types] after p. 4:
typedef see below const_void_pointer;4 Type: Alloc::const_void_pointer if such a type exists; otherwise, pointer_traits<pointer>::rebind<const void>.
typedef see below reference;? Type: Alloc::reference if such a type exists; otherwise, value_type&.
typedef see below const reference;? Type: Alloc::const_reference if such a type exists; otherwise, const value_type&.
Add the following descriptions at the beginning of 20.6.8.2 [allocator.traits.members]:
static pointer address(Alloc& a, reference r) noexcept;? Returns: a.address(r) if that expression is well-formed; otherwise, pointer_traits<pointer>::pointer_to(r).
static const_pointer address(Alloc& a, const_reference r) noexcept;? Returns: a.address(r) if that expression is well-formed; otherwise, pointer_traits<const_pointer>::pointer_to(r).
static pointer allocate(Alloc& a, size_type n);1 Returns: a.allocate(n).
Add the following typdef and member function declarations to scoped_allocator_adaptor 20.12 [allocator.adaptor]:
template <class OuterAlloc, class... InnerAllocs> class scoped_allocator_adaptor : public OuterAlloc { ... typedef typename OuterTraits::reference reference; typedef typename OuterTraits::const_reference const_reference; ... pointer address(reference r) noexcept; const_pointer address(const_reference r) noexcept; pointer allocate(size_type n); ...
Add the following prototype descriptions to 20.12.4 [allocator.adaptor.members]:
const outer_allocator_type& outer_allocator() const noexcept;4 Returns: static_cast<const Outer&>(*this).
pointer address(reference r) noexcept;? Returns: allocator_traits<OuterAlloc>::address(outer_allocator(), r).
const_pointer address(const_reference r) noexcept;? Returns: allocator_traits<OuterAlloc>::address(outer_allocator(), r).
pointer allocate(size_type n);5 Returns: allocator_traits<OuterAlloc>::allocate(outer_allocator(), n).
Change the nested typedefs reference and const_reference to:
typedef typename allocator_traits<Allocator>::reference reference; typedef typename allocator_traits<Allocator>::const_reference const_reference;
for each of the following class templates:
basic_string 21.4 [basic.string]
deque 23.3.3 [deque]
forward_list 23.3.4 [forwardlist]
list 23.3.5 [list]
vector 23.3.6 [vector]
map 23.4.4 [map]
multimap 23.4.5 [multimap]
set 23.4.6 [set]
multiset 23.4.7 [multiset]
Change the nested typedefs reference and const_reference to:
typedef typename allocator_traits<Allocator>::reference reference; typedef typename allocator_traits<Allocator>::const_reference const_reference;
and change the nested typedefs pointer and const_pointer to:
typedef typename allocator_traits<Allocator>::pointer pointer; typedef typename allocator_traits<Allocator>::const_pointer const_pointer;
for each of the following class templates:
unordered_map 23.5.4 [unord.map]
unordered_multimap 23.5.5 [unord.multimap]
unordered_set 23.5.6 [unord.set]
unordered_multiset 23.5.7 [unord.multiset]
Edit the class template synopsis of match_results in 28.10 [re.results] as indicated:
template <class BidirectionalIterator, class Allocator = allocator<sub_match<BidirectionalIterator> > class match_results { public: typedef sub_match<BidirectionalIterator> value_type; typedefconst value_type&typename allocator_traits<Allocator>::const_reference const_reference; typedef const_reference reference; ... };
Section: 24.3 [iterator.synopsis] Status: Tentatively NAD Future Submitter: Alisdair Meredith Opened: 2010-02-16 Last modified: 2010-11-13
Discussion:
The iter_swap function template appears in the <algorithm> header, yet its main use is in building further algorithms, not calling existing ones. The main clients are implementers of data structures and their iterators, so it seems most appropriate to place the template in the <iterator> header instead.
Note that this is not an issue for implementers of the standard library, as they rarely use the standard headers directly, designing a more fine-grained set of headers for their own internal use. This option is not available to customers of the standard library.
Note that we cannot remove iter_swap from <algorithm> without breaking code, but there is no reason we cannot offer the same declaration via two standard headers. Alternatively, require <algorithm> to #include <iterator>, but introducing the dependency on the iterator adaptors seems un-necessary.
[ ]
Discussed possibly moving to <utility> but don't like that. Some not seeing this as a defect, and want to keep it in <algorithm>. No one seems to feel strongly about moving to <iterator>.
Proposed resolution:
Add the declaration of iter_swap to the <iterator> header synopsis (24.3 [iterator.synopsis]), with a note that it is documented in clause 25 [algorithms].
... template <class T, size_t N> T* end(T (&array)[N]); // documented in 25 [algorithms] template<class ForwardIterator1, class ForwardIterator2> void iter_swap(ForwardIterator1 a, ForwardIterator2 b);
Section: 23.2 [container.requirements] Status: Deferred Submitter: Nicolai Josuttis Opened: 2010-03-10 Last modified: 2010-11-15
View all other issues in [container.requirements].
View all issues with Deferred status.
Discussion:
Abstract:
In general, it seems that in a couple of places container behavior is not described in requirement tables although it is a general behavior.
History:
Issue 676 added move semantics to unordered containers. For the added insert functions the Editor requested to put their semantic description into a requirements table rather than describing them for each container individually. The text however was taken from the associative containers, where we also have the semantics for each container described. Also, 1034 is to some extend requesting a clarification of the requirement tables and it turned out that in other places we have the same problem (e.g. we have no general requirement for type pointer and const_pointer although each container has them with issue 1306).
From my personal list of functions in requirement tables and containers, the following types/functions are missing in requirement tables:
all copy constructors, copy constructors with allocator, assignment operators, and insert operators with move semantics for associative and unordered containers
ContType c1(c2&&) ContType c1(c2&&,alloc) c1 = c2&& c.insert(val&&) c.insert(pos,val&&)
As a special case, we lack the following requirements for all sequence containers BUT array (so special wording or a new container category is required):
constructor with only a size argument
ContType c(num)
copy constructor with allocator and move semantics
ContType c1(c2&&,alloc)
all constructors that insert multiple elements with additional allocator
ContType c(num, val,alloc) ContType c(beg, end,alloc) ContType c(initlist,alloc)
all resize functiuons:
c.resize(num) c.resize(num,val)
Note that we also might have to add additional requirements on other places for sequence containers because having an allocator requires additional statements for the treatment of the allocators. E.g. swap for containers with allocators is not specified in any requirement table.
And finally, if we have the requirements in the requirements tables, we can remove the corresponding descriptions for the individual container. However, note that sequence container requirements have NO complexity column, so that we still need container specific descriptions for the functions listed there.
[ 2010 Batavia ]
While there is consensus that further cleaning up the container requirement tables would be a good thing, there is no feeling that this must be done in time for 0x. The issue remains open, but Deferred.
Proposed resolution:
Section: 17.6.3.4 [hash.requirements] Status: Ready Submitter: Daniel Krügler Opened: 2010-03-26 Last modified: 2011-02-21
View all issues with Ready status.
Discussion:
The currently added Hash requirements demand in Table 40 — Hash requirements [hash]:
Table 40 — Hash requirements [hash] Expression Return type Requirement h(k) size_t Shall not throw exceptions. [..]
While it surely is a generally accepted idea that hash function objects should not throw exceptions, this basic constraint for such a fundamental requirement set does neither match the current library policy nor real world cases:
The new definition goes beyond the original hash requirements as specified by SGI library in regard to the exception requirement:
Even though the majority of all known move, swap, and hash functions won't throw and in some cases must not throw, it seems like unnecessary over-constraining the definition of a Hash functor not to propagate exceptions in any case and it contradicts the general principle of C++ to impose such a requirement for this kind of fundamental requirement.
[ 2010-11-11 Daniel asks the working group whether they would prefer a replacement for the second bullet of the proposed resolution (a result of discussing this with Alberto) of the form: ]
Add to 20.8.12 [unord.hash]/1 a new bullet:
1 The unordered associative containers defined in Clause 23.5 use specializations of the class template hash as the default hash function. For all object types Key for which there exists a specialization hash<Key>, the instantiation hash<Key> shall:
- satisfy the Hash requirements (20.2.4), with Key as the function call argument type, the DefaultConstructible requirements (33), the CopyAssignable requirements (37),
- be swappable (20.2.2) for lvalues,
- provide two nested types result_type and argument_type which shall be synonyms for size_t and Key, respectively,
- satisfy the requirement that if k1 == k2 is true, h(k1) == h(k2) is also true, where h is an object of type hash<Key> and k1 and k2 are objects of type Key,
.- satisfy the requirement noexcept(h(k)) == true, where h is an object of type hash<Key> and k is an object of type Key, unless hash<Key> is a user-defined specialization that depends on at least one user-defined type.
[Batavia: Closed as NAD Future, then reopened. See the wiki for Tuesday.]
Proposed resolution:
Change Table 40 — Hash requirements [hash] as indicated:
Table 40 — Hash requirements [hash] Expression Return type Requirement h(k) size_t Shall not throw exceptions.[..]
Add to 20.8.12 [unord.hash]/1 a new bullet:
1 The unordered associative containers defined in Clause 23.5 use specializations of the class template hash as the default hash function. For all object types Key for which there exists a specialization hash<Key>, the instantiation hash<Key> shall:
- satisfy the Hash requirements (20.2.4), with Key as the function call argument type, the DefaultConstructible requirements (33), the CopyAssignable requirements (37),
- be swappable (20.2.2) for lvalues,
- provide two nested types result_type and argument_type which shall be synonyms for size_t and Key, respectively,
- satisfy the requirement that if k1 == k2 is true, h(k1) == h(k2) is also true, where h is an object of type hash<Key> and k1 and k2 are objects of type Key,
.- satisfy the requirement that the expression h(k), where h is an object of type hash<Key> and k is an object of type Key, shall not throw an exception, unless hash<Key> is a user-defined specialization that depends on at least one user-defined type.
Section: 17 [library] Status: Open Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [library].
View all other issues in [library].
View all issues with Open status.
Discussion:
Addresses GB-61
All library types should have non-throwing move constructors and move-assignment operators unless wrapping a type with a potentially throwing move operation. When such a type is a class-template, these operations should have a conditional noexcept specification.
There are many other places where a noexcept specification may be considered, but the move operations are a special case that must be called out, to effectively support the move_if_noexcept function template.
[ Resolution proposed by ballot comment: ]
Review every class and class template in the library. If noexcept move constructor/assignment operators can be implicitly declared, then they should be implicitly declared, or explicitly defaulted. Otherwise, a move constructor/move assignment operator with a noexcept exception specification should be provided.
[ 2010-10-31 Daniel comments: ]
The proposed resolution of n3157 would satisfy this request.
Proposed resolution:
See n3157
Section: 17 [library] Status: Open Submitter: BSI Opened: 2010-08-25 Last modified: 2010-10-25
View other active issues in [library].
View all other issues in [library].
View all issues with Open status.
Discussion:
Addresses GB-64
There are a number of unspecified types used throughout the library, such as the container iterators. Many of these unspecified types have restrictions or expectations on their behaviour in terms of exceptions. Are they permitted or required to use exception specifications, more specifically the new noexcept specification? For example, if vector<T>::iterator is implemented as a native pointer, all its operations will have an (effective) noexcept specification. If the implementation uses a class type to implement this iterator, is it permitted or required to support that same guarantee?
[ Resolution proposed by ballot comment ]
Clearly state the requirements for exception specifications on all unspecified library types. For example, all container iterator operations should be conditionally noexcept, with the condition matching the same operation applied to the allocator's pointer_type, a certain subset of which are already required not to throw.
Proposed resolution:
Section: 17 [library] Status: Open Submitter: BSI Opened: 2010-08-25 Last modified: 2010-10-25
View other active issues in [library].
View all other issues in [library].
View all issues with Open status.
Discussion:
Addresses GB-65
Nothrowing swap operations are key to many C++ idioms, notably the common copy/swap idiom to provide the strong exception safety guarantee.
[ Resolution proposed by ballot comment ]
Where possible, all library types should provide a swap operation with an exception specification guaranteeing no exception shall propagate. Where noexcept(true) cannot be guaranteed to not terminate the program, and the swap in questions is a template, an exception specification with the appropriate conditional expression could be specified.
Proposed resolution:
Section: 17 [library] Status: Open Submitter: Switzerland Opened: 2010-08-25 Last modified: 2011-02-28
View other active issues in [library].
View all other issues in [library].
View all issues with Open status.
Discussion:
Addresses CH-18
The general approach on moving is that a library object after moving out is in a "valid but unspecified state". But this is stated at the single object specifications, which is error prone (especially if the move operations are implicit) and unnecessary duplication.
[ Resolution propsed by ballot comment ]
Consider putting a general statement to the same effect into clause 17.
[2010-11-05 Beman provides exact wording. The wording was inspired by Dave Abrahams' message c++std-lib-28958, and refined with help from Alisdair, Daniel, and Howard. ]
[2011-02-25 P/R wording superseded by N3241. ]
Proposed resolution:
Resolved by N3241
Section: 17.6.1.3 [compliance] Status: Open Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-28
View all other issues in [compliance].
View all issues with Open status.
Discussion:
Addresses GB-55
The <thread> header uses duration types, found in the <chrono> header, and which rely on the ratio types declared in the <ratio> header.
[ Extracts from lengthy Rapperswil discussion: ]
There is a concern that this issue is a misunderstanding of the actual requirements of a free-standing implementation to support the <thread> header. In general, a free-standanding implementation will provide an empty header, specifically so that a user can test for the absence of the _ _ STDCPP_THREADS _ _ macro. This idiom as used as there is no portable way to test for the lack of a header.
At this point, it was suggested the NB comment is trying to solve the wrong problem, and that _ _ STDCPP_THREADS _ _ should be a pre-defined macro in clause 16 that can be tested before including <thread>. That would remove the need to add additional headers to the free-standanding requirements.
It is worth noting that Japan requested <ratio> as a free-standing header in their CD1 comments. No-one seemed keen to require clocks of a free-standing implementation though.
Detlef volunteers to look at a way to redraft 17.6.1.3 p3.
[ Original resolution proposed by NB comment: ]
Add the <chrono> and <ratio> headers to the freestanding requirements.
It might be necessary to address scaled-down expectations of clock support in a freestanding environment, much like <thread>.
[2011-02-25: Alberto drafts wording]
Proposed resolution:
Add a new entry in Table 14 — C++ library headers:
Table 14 — C++ library headers … <iterator> <library_support> <limits> …
Remove the last row 30.3 [thread.threads] <threads> from Table 16 — C++ headers for freestanding implementations and insert a new one instead (To the editor: For the actual target Clause please see the comment in bullet 5 of this proposed resolution):
Table 16 — C++ headers for freestanding implementations Subclause Header(s) … 30.3 [thread.threads] Threads<thread>?? Library support <library_support>
Modify paragraph 17.6.1.3 [compliance] p. 3:
3 The supplied version of the header <cstdlib> shall declare at least the functions abort, atexit, at_quick_exit, exit, and quick_exit (18.5).
The supplied version of the header <thread> shall meet the same requirements as for a hosted implementation or including it shall have no effect. The other headers listed in this table shall meet the same requirements as for a hosted implementation. A program can detect the presence of standard headers not listed in Table 16 using the facilities provided by the <library_support> header.
Remove the following line from the header <thread> synopsis in 30.3 [thread.threads] p. 1:
namespace std {#define __STDCPP_THREADS__ __cplusplusclass thread; [...] }
Add a new section in Clause 18 or 20 (or any other suitable place at the editor's discretion):
?? Library support [library.support]
The header <library_support> defines an implementation-defined set of macros to allow a program detect the presence of standard headers in freestanding implementations. [Note: Hosted implementations shall provide all standard headers, thus shall provide all macros. — end note]
For each standard header listed in Tables 14 (C++ library headers) and 15 (C++ headers for C library facilities) that is provided by the implementation, <library_support> shall define a macro with name
_ _HAS_XXX_HEADER_ _
whereXXX
is replaced by the uppercase version of the name of the header. Each such macro shall expand to the value_ _cplusplus
. [Example:#include <library_support> #ifdef _ _HAS_THREADS_HEADER_ _ #include <threads> // code that exploit the presence of threads #else // fallback code that doesn't rely on threads #endif— end example]
No other standard header shall define macros with a name beginning with
_ _HAS_
and ending with_HEADER_ _
.
Section: 18.8.5 [propagation] Status: Open Submitter: Switzerland Opened: 2010-08-25 Last modified: 2010-10-24
View other active issues in [propagation].
View all other issues in [propagation].
View all issues with Open status.
Discussion:
Addresses CH-19
It is not clear how exception_ptr is synchronized.
[ Resolution proposed by ballot comment ]
Make clear that accessing in different threads multiple exception_ptr objects that all refer to the same exception introduce a race.
Proposed resolution:
Section: 18.8.5 [propagation] Status: Open Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [propagation].
View all other issues in [propagation].
View all issues with Open status.
Discussion:
Addresses GB-74
One idea for the exception_ptr type was that a reference-counted implementation could simply 'reactivate' the same exception object in the context of a call to rethrow_exception. Such an implementation would allow the same exception object to be active in multiple threads (such as when multiple threads join on a shared_future) and introduce potential data races in any exception handler that catches exceptions by reference - notably existing library code written before this capability was added. rethrow_exception should always make a copy of the target exception object.
Proposed resolution:
Add the following to 18.8.5, [propogation]
Throws: a copy of the exception object to which p refers.
Section: 19 [diagnostics] Status: Tentatively NAD Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View all issues with Tentatively NAD status.
Discussion:
Addresses GB-75
None of the exception types defined in clause 19 are allowed to throw an exception on copy or move operations, but there is no clear specification that the operations have an exception specification to prove it. Note that the implicitly declared constructors, taking the exception specification from their base class (ultimately std::exception) will implicitly generate a noexcept exception specification if all of their data members similarly declare noexcept operations. As the representation is unspecified, we cannot assume nonthrowing operations unless we explicitly state this as a constraint on the implementation.
[ Resolution proposed by ballot comment: ]
Add a global guarantee that all exception types defined in clause 19 that rely on implicitly declared operations have a non-throwing exception specification on those operations.
[ 2010 Batavia: ]
This is addressed by the current words in 18.8.1 [exception], p2
Each standard library class T that derives from class exception shall have a publicly accessible copy constructor and a publicly accessible copy assignment operator that do not exit with an exception.
Proposed resolution:
Section: 17.6.3.1 [utility.arg.requirements] Status: Open Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-28
View all other issues in [utility.arg.requirements].
View all issues with Open status.
Discussion:
Addresses US-85
20.2.1 Table 34 "MoveConstructible requirements" says "Note: rv remains a valid object. Its state is unspecified". Some components give stronger guarantees. For example, moved-from shared_ptrs are guaranteed empty (20.9.11.2.1/25). In general, what the standard really should say (preferably as a global blanket statement) is that moved-from objects can be destroyed and can be the destination of an assignment. Anything else is radioactive. For example, containers can be "emptier than empty". This needs to be explicit and required generally.
Note: The last time that one of us mentioned "emptier than empty" (i.e. containers missing sentinel nodes, etc.) the objection was that containers can store sentinel nodes inside themselves in order to avoid dynamically allocating them. This is unacceptable because
(a) it forces existing implementations (i.e. Dinkumware's, Microsoft's, IBM's, etc.) to change for no good reason (i.e. permitting more operations on moved-from objects), and
(b) it invalidates end-iterators when swapping containers. (The Working Paper currently permits end-iterator invalidation, which we consider to be wrong, but that's a separate argument. In any event, mandating end-iterator invalidation is very different from permitting it.)
[ Resolution proposed in ballot comment ]
State as a general requirement that moved-from objects can be destroyed and can be the destination of an assignment. Any other use is undefined behavior.
Proposed resolution:
Resolved by N3241
Section: 20.4.2.4 [tuple.creation] Status: Ready Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View all other issues in [tuple.creation].
View all issues with Ready status.
Discussion:
Addresses GB-88
The tuple_cat template consists of four overloads and that can concatenate only two tuples. A single variadic signature that can concatenate an arbitrary number of tuples would be preferred.
[ Resolution proposed by ballot comment: ]
Adopt a simplified form of the proposal in n2975, restricted to tuples and neither requiring nor outlawing support for other tuple-like types.
[ 2010 Rapperswil: Alisdair to provide wording. ]
[ 2010-11-06: Daniel comments and proposes some alternative wording: ]
There are some problems in the wording: First, even though the result type tuple<see below> implies it, the specification of the contained tuple element types is missing. Second, the term "tuple protocol" is not defined anywhere and I see no reason why this normative wording should not be a non-normative note. We could at least give a better approximation, maybe "tuple-like protocol" as indicated from header <utility> synopsis. Further, it seems to me that the effects need to contain a combination of std::forward with the call of get. Finally I suggest to replace the requirements Move/CopyConstructible by proper usage of is_constructible, as indicated by n3140.
[ 2010 Batavia ]
Moved to Ready with Daniel's improved wording.
Proposed resolution:
Note: This alternate proposed resolution works only if 1191 has been accepted.
namespace std { ... // 20.4.2.4, tuple creation functions: const unspecified ignore; template <class... Types> tuple<VTypes...> make_tuple(Types&&...); template <class... Types> tuple<ATypes...> forward_as_tuple(Types&&...); template<class... Types> tuple<Types&...> tie(Types&...);template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(const tuple<TTypes...>&, const tuple<UTypes...>&); template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(tuple<TTypes...>&&, const tuple<UTypes...>&); template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(const tuple<TTypes...>&, tuple<UTypes...>&&); template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(tuple<TTypes...>&&, tuple<UTypes...>&&);template <class... Tuples> tuple<CTypes...> tuple_cat(Tuples&&...); ...
template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(const tuple<TTypes...>& t, const tuple<UTypes...>& u);
8 Requires: All the types in TTypes shall be CopyConstructible (Table 35). All the types in UTypes shall be CopyConstructible (Table 35).
9 Returns: A tuple object constructed by copy constructing its first sizeof...(TTypes) elements from the corresponding elements of t and copy constructing its last sizeof...(UTypes) elements from the corresponding elements of u.template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(tuple<TTypes...>&& t, const tuple<UTypes...>& u);
10 Requires: All the types in TTypes shall be MoveConstructible (Table 34). All the types in UTypes shall be CopyConstructible (Table 35).
11 Returns: A tuple object constructed by move constructing its first sizeof...(TTypes) elements from the corresponding elements of t and copy constructing its last sizeof...(UTypes) elements from the corresponding elements of u.template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(const tuple<TTypes...>& t, tuple<UTypes...>&& u);
12 Requires: All the types in TTypes shall be CopyConstructible (Table 35). All the types in UTypes shall be MoveConstructible (Table 34).
13 Returns: A tuple object constructed by copy constructing its first sizeof...(TTypes) elements from the corresponding elements of t and move constructing its last sizeof...(UTypes) elements from the corresponding elements of u.template <class... TTypes, class... UTypes> tuple<TTypes..., UTypes...> tuple_cat(tuple<TTypes...>&& t, tuple<UTypes...>&& u);
14 Requires: All the types in TTypes shall be MoveConstructible (Table 34). All the types in UTypes shall be MoveConstructible (Table 34).
15 Returns: A tuple object constructed by move constructing its first sizeof...(TTypes) elements from the corresponding elements of t and move constructing its last sizeof...(UTypes) elements from the corresponding elements of u.template <class... Tuples> tuple<CTypes...> tuple_cat(Tuples&&... tpls);8 Let Ti be the ith type in Tuples, Ui be remove_reference<Ti>::type, and tpi be the ith parameter in the function parameter pack tpls, where all indexing is zero-based in the following paragraphs of this sub-clause [tuple.creation].
9 Requires: For all i, Ui shall be the type cvi tuple<Argsi...>, where cvi is the (possibly empty) ith cv-qualifier-seq, and Argsi is the parameter pack representing the element types in Ui. Let Aik be the kith type in Argsi, then for all Aik the following requirements shall be satisfied: If Ti is deduced as an lvalue reference type, then is_constructible<Aik, cvi Aik&>::value == true, otherwise is_constructible<Aik, cvi Aik&&>::value == true.
10 Remarks: The types in CTypes shall be equal to the ordered sequence of the expanded types Args0..., Args1..., Argsn-1..., where n equals sizeof...(Tuples). Let ei... be the ith ordered sequence of tuple elements of the result tuple object corresponding to the type sequence Argsi.
11 Returns: A tuple object constructed by initializing the kith type element eik in ei... with get<ki>(std::forward<Ti>(tpi)) for each valid ki and each element group ei in order.
12 [Note: An implementation may support additional types in the parameter pack Tuples, such as pair and array that support the tuple-like protocol. -- end note]
Section: 28.8 [re.regex] Status: Open Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [re.regex].
View all other issues in [re.regex].
View all issues with Open status.
Duplicate of: 1451
Discussion:
Addresses US-104, US-141
std::basic_regex should have an allocator for all the reasons that a std::string does. For example, I can use boost::interprocess to put a string or vector in shared memory, but not a regex.
[ Resolution proposed by ballot comment ]
Add allocators to regexes
[ 2010-10-24 Daniel adds: ]
Accepting n3171 would solve this issue.
Proposed resolution:
See n3171.
Section: 20.6 [memory] Status: Ready Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View all other issues in [memory].
View all issues with Ready status.
Discussion:
Addresses GB-99
One reason that the unique_ptr constructor taking a nullptr_t argument is not explicit is to allow conversion of nullptr to unique_ptr in contexts like equality comparison. Unfortunately operator== for unique_ptr is a little more clever than that, deducing template parameters for both arguments. This means that nullptr does not get deduced as unique_ptr type, and there are no other comparison functions to match.
[ Resolution proposed by ballot comment: ]
Add the following signatures to 20.6 [memory] p.1, <memory> header synopsis:
template<typename T, typename D> bool operator==(const unique_ptr<T, D> & lhs, nullptr_t); template<typename T, typename D> bool operator==(nullptr_t, const unique_ptr<T, D> & rhs); template<typename T, typename D> bool operator!=(const unique_ptr<T, D> & lhs, nullptr_t); template<typename T, typename D> bool operator!=(nullptr_t, const unique_ptr<T, D> & rhs);
[ 2010-11-02 Daniel comments and provides a proposed resolution: ]
The same problem applies to shared_ptr as well: In both cases there are no conversions considered because the comparison functions are templates. I agree with the direction of the proposed resolution, but I believe it would be very surprising and inconsistent, if given a smart pointer object p, the expression p == nullptr would be provided, but not p < nullptr and the other relational operators. According to 5.9 [expr.rel] they are defined if null pointer values meet other pointer values, even though the result is unspecified for all except some trivial ones. But null pointer values are nothing special here: The Library already defines the relational operators for both unique_ptr and shared_ptr and the outcome of comparing non-null pointer values will be equally unspecified. If the idea of supporting nullptr_t arguments for relational operators is not what the committee prefers, I suggest at least to consider to remove the existing relational operators for both unique_ptr and shared_ptr for consistency. But that would not be my preferred resolution of this issue.
The number of overloads triple the current number, but I think it is much clearer to provide them explicitly instead of adding wording that attempts to say that "sufficient overloads" are provided. The following proposal makes the declarations explicit. Additionally, the proposal adds the missing declarations for some shared_ptr comparison functions for consistency.
[ 2010-11-03 Daniel adds: ]
Issue 1297 is remotely related. The following proposed resolution splits this bullet into sub-bullets A and B. Sub-bullet A would also solve 1297, but sub-bullet B would not.
A further remark in regard to the proposed semantics of the ordering of nullptr against other pointer(-like) values: One might think that the following definition might be superior because of simplicity:template<class T> bool operator<(const shared_ptr<T>& a, nullptr_t); template<class T> bool operator>(nullptr_t, const shared_ptr<T>& a);Returns: false.
The underlying idea behind this approach is the assumption that nullptr corresponds to the least ordinal pointer value. But this assertion does not hold for all supported architectures, therefore this approach was not followed because it would lead to the inconsistency, that the following assertion could fire:
shared_ptr<int> p(new int); shared_ptr<int> null; bool v1 = p < nullptr; bool v2 = p < null; assert(v1 == v2);
Proposed resolution:
Wording changes are against N3126.
namespace std { [..] // 20.9.10 Class unique_ptr: template <class T> class default_delete; template <class T> class default_delete<T[]>; template <class T, class D = default_delete<T>> class unique_ptr; template <class T, class D> class unique_ptr<T[], D>; template <class T1, class D1, class T2, class D2> bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T, class D> bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator==(nullptr_t, const unique_ptr<T, D>& x) noexcept; template <class T, class D> bool operator!=(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator!=(nullptr_t, const unique_ptr<T, D>& x) noexcept; template <class T, class D> bool operator<(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator<(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator<=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator<=(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>=(nullptr_t, const unique_ptr<T, D>& x); // 20.9.11.1, Class bad_weak_ptr: class bad_weak_ptr; // 20.9.11.2, Class template shared_ptr: template<class T> class shared_ptr; // 20.9.11.2.7, shared_ptr comparisons: template<class T, class U> bool operator==(shared_ptr<T> const& a, shared_ptr<U> const& b); template<class T, class U> bool operator!=(shared_ptr<T> const& a, shared_ptr<U> const& b); template<class T, class U> bool operator<(shared_ptr<T> const& a, shared_ptr<U> const& b); template<class T, class U> bool operator>(shared_ptr<T> const& a, shared_ptr<U> const& b); template<class T, class U> bool operator<=(shared_ptr<T> const& a, shared_ptr<U> const& b); template<class T, class U> bool operator>=(shared_ptr<T> const& a, shared_ptr<U> const& b); template<class T> bool operator==(shared_ptr<T> const& a, nullptr_t) noexcept; template<class T> bool operator==(nullptr_t, shared_ptr<T> const& a) noexcept; template<class T> bool operator!=(shared_ptr<T> const& a, nullptr_t) noexcept; template<class T> bool operator!=(nullptr_t, shared_ptr<T> const& a) noexcept; template<class T> bool operator<(shared_ptr<T> const& a, nullptr_t) noexcept; template<class T> bool operator<(nullptr_t, shared_ptr<T> const& a) noexcept; template>class T> bool operator>(shared_ptr<T> const& a, nullptr_t) noexcept; template>class T> bool operator>(nullptr_t, shared_ptr<T> const& a) noexcept; template<class T> bool operator<=(shared_ptr<T> const& a, nullptr_t) noexcept; template<class T> bool operator<=(nullptr_t, shared_ptr<T> const& a) noexcept; template>class T> bool operator>=(shared_ptr<T> const& a, nullptr_t) noexcept; template>class T> bool operator>=(nullptr_t, shared_ptr<T> const& a) noexcept; [..] }
namespace std { [..] template <class T1, class D1, class T2, class D2> bool operator==(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator!=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T1, class D1, class T2, class D2> bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y); template <class T, class D> bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator==(nullptr_t, const unique_ptr<T, D>& x) noexcept; template <class T, class D> bool operator!=(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator!=(nullptr_t, const unique_ptr<T, D>& x) noexcept; template <class T, class D> bool operator<(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator<(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator<=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator<=(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>=(nullptr_t, const unique_ptr<T, D>& x); }
template <class T1, class D1, class T2, class D2> bool operator<(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);? Requires: Let CT be common_type<unique_ptr<T1, D1>::pointer, unique_ptr<T2, D2>::pointer>::type. Then the specialization less<CT> shall be a function object type ([function.objects]) that induces a strict weak ordering ([alg.sorting]) on the pointer values.
4 Returns: less<CT>()(x.get(), y.get())
x.get() < y.get().? Remarks: If unique_ptr<T1, D1>::pointer is not implicitly convertible to CT or unique_ptr<T2, D2>::pointer is not implicitly convertible to CT, the program is ill-formed.
template <class T1, class D1, class T2, class D2> bool operator<=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);5 Returns: !(y < x)
x.get() <= y.get().template <class T1, class D1, class T2, class D2> bool operator>(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);6 Returns: (y < x)
x.get() > y.get().template <class T1, class D1, class T2, class D2> bool operator>=(const unique_ptr<T1, D1>& x, const unique_ptr<T2, D2>& y);7 Returns: !(x < y)
x.get() >= y.get().
template <class T, class D> bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator==(nullptr_t, const unique_ptr<T, D>& x) noexcept;? Returns: !x.
template <class T, class D> bool operator!=(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator!=(nullptr_t, const unique_ptr<T, D>& x) noexcept;? Returns: (bool) x.
template <class T, class D> bool operator<(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>(nullptr_t, const unique_ptr<T, D>& x);? Requires: The specialization less<unique_ptr<T, D>::pointer> shall be a function object type ([function.objects]) that induces a strict weak ordering ([alg.sorting]) on the pointer values.
? Returns: less<unique_ptr<T, D>::pointer>()(x.get(), nullptr).
template <class T, class D> bool operator<(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>(const unique_ptr<T, D>& x, nullptr_t);? Requires: The specialization less<unique_ptr<T, D>::pointer> shall be a function object type ([function.objects]) that induces a strict weak ordering ([alg.sorting]) on the pointer values.
? Returns: less<unique_ptr<T, D>::pointer>()(nullptr, x.get()).
template <class T, class D> bool operator<=(const unique_ptr<T, D>& x, nullptr_t); template <class T, class D> bool operator>=(nullptr_t, const unique_ptr<T, D>& x);? Returns: !(nullptr < x).
template <class T, class D> bool operator<=(nullptr_t, const unique_ptr<T, D>& x); template <class T, class D> bool operator>=(const unique_ptr<T, D>& x, nullptr_t);? Returns: !(x < nullptr).
template <class T, class D> bool operator==(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator==(nullptr_t, const unique_ptr<T, D>& x) noexcept;? Returns: !x.
template <class T, class D> bool operator!=(const unique_ptr<T, D>& x, nullptr_t) noexcept; template <class T, class D> bool operator!=(nullptr_t, const unique_ptr<T, D>& x) noexcept;? Returns: (bool) x.
template <class T, class D> bool operator<(const unique_ptr<T, D>& x, nullptr_t);? Returns: x.get() < nullptr.
template <class T, class D> bool operator<(nullptr_t, const unique_ptr<T, D>& x);? Returns: nullptr < x.get().
template <class T, class D> bool operator<=(const unique_ptr<T, D>& x, nullptr_t);? Returns: x.get() <= nullptr.
template <class T, class D> bool operator<=(nullptr_t, const unique_ptr<T, D>& x);? Returns: nullptr <= x.get().
template <class T, class D> bool operator>(const unique_ptr<T, D>& x, nullptr_t);? Returns: x.get() > nullptr.
template <class T, class D> bool operator>(nullptr_t, const unique_ptr<T, D>& x);? Returns: nullptr > x.get().
template <class T, class D> bool operator>=(const unique_ptr<T, D>& x, nullptr_t);? Returns: x.get() >= nullptr.
template <class T, class D> bool operator>=(nullptr_t, const unique_ptr<T, D>& x);? Returns: nullptr >= x.get().
namespace std { [..] // 20.9.11.2.7, shared_ptr comparisons: template<class T, class U> bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b); template<class T, class U> bool operator!=(const shared_ptr<T>& a, const shared_ptr<U>& b); template<class T, class U> bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b); template<class T, class U> bool operator>(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> bool operator<=(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T, class U> bool operator>=(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept; template<class T> bool operator==(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator==(nullptr_t, const shared_ptr<T>& a) noexcept; template<class T> bool operator!=(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator!=(nullptr_t, const shared_ptr<T>& a) noexcept; template<class T> bool operator<(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator<(nullptr_t, const shared_ptr<T>& a) noexcept; template>class T> bool operator>(const shared_ptr<T>& a, nullptr_t) noexcept; template>class T> bool operator>(nullptr_t, const shared_ptr<T>& a) noexcept; template<class T> bool operator<=(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator<=(nullptr_t, const shared_ptr<T>& a) noexcept; template>class T> bool operator>=(const shared_ptr<T>& a, nullptr_t) noexcept; template>class T> bool operator>=(nullptr_t, const shared_ptr<T>& a) noexcept; [..] }
template<class T> bool operator==(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator==(nullptr_t, const shared_ptr<T>& a) noexcept;? Returns: !a.
template<class T> bool operator!=(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator!=(nullptr_t, const shared_ptr<T>& a) noexcept;? Returns: (bool) a.
template<class T> bool operator<(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator>(nullptr_t, const shared_ptr<T>& a) noexcept;? Returns: less<T*>()(a.get(), nullptr).
template<class T> bool operator<(nullptr_t, const shared_ptr<T>& a) noexcept; template<class T> bool operator>(const shared_ptr<T>& a, nullptr_t) noexcept;? Returns: less<T*>()(nullptr, a.get()).
template<class T> bool operator<=(const shared_ptr<T>& a, nullptr_t) noexcept; template<class T> bool operator>=(nullptr_t, const shared_ptr<T>& a) noexcept;? Returns: !(nullptr < a).
template<class T> bool operator<=(nullptr_t, const shared_ptr<T>& a) noexcept; template<class T> bool operator>=(const shared_ptr<T>& a, nullptr_t) noexcept;? Returns: !(a < nullptr).
Section: 20.6.4 [util.dynamic.safety] Status: Ready Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View all other issues in [util.dynamic.safety].
View all issues with Ready status.
Discussion:
Addresses GB-103
The precondition to calling declare_no_pointers is that no bytes in the range "have been previously registered" with this call. As written, this precondition includes bytes in ranges, even after they have been explicitly unregistered with a later call to undeclare_no_pointers.
Proposed resolution:
Update 20.6.4 [util.dynamic.safety] p.9:
void declare_no_pointers(char *p, size_t n);9 Requires: No bytes in the specified range
have been previously registeredare currently registered with declare_no_pointers(). If the specified range is in an allocated object, then it must be entirely within a single allocated object. The object must be live until the corresponding undeclare_no_pointers() call. [..]
Section: 20.11.7.3 [time.clock.hires] Status: Tentatively NAD Submitter: INCITS Opened: 2010-08-25 Last modified: 2010-11-14
View all issues with Tentatively NAD status.
Discussion:
Addresses US-112
What it means for high_resolution_clock to be a synonym is undefined. If it may or may not be a typedef, then certain classes of programs become unportable.
[ Resolution proposed in ballot comment ]
Require that it be a distinct class type.
[ 2010 Batavia ]
This is not a defect. Threre are a number of places in the standard where we allow implentations to choose their preferred technique, the most obvious example being the iterator/const_iterator types of set.
Typically, this means it is not portable to declare function overloads that differ only in their use of these types.
Proposed resolution:
Section: 23.3.3.3 [deque.capacity] Status: Ready Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View all other issues in [deque.capacity].
View all issues with Ready status.
Discussion:
Addresses GB-113
There is no mention of what happens if sz==size(). While it obviously does nothing I feel a standard needs to say this explicitely.
[ 2010 Batavia ]
Accepted with a simplified resolution turning one of the < comparisons into <=.
Proposed resolution:
Ammend [deque.capacity]
void resize(size_type sz);
Effects: If sz <= size(), equivalent to erase(begin() +
sz, end());. If size() < sz, appends sz - size() default
constructedvalue initialized elements to the sequence.
Section: 23.3.5.3 [list.capacity] Status: Ready Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View all other issues in [list.capacity].
View all issues with Ready status.
Discussion:
Addresses GB-115
There is no mention of what happens if sz==size(). While it obviously does nothing I feel a standard needs to say this explicitely.
[ Resolution proposed in ballot comment ]
Express the semantics as pseudo-code similarly to the way it is done for the copying overload that follows (in p3). Include an else clause that does nothing and covers the sz==size() case.
[ 2010 Batavia ]
Accepted with a simplified resolution turning one of the < comparisons into <=.
Proposed resolution:
Ammend [list.capacity] p1:
void resize(size_type sz);
Effects: If sz <= size(), equivalent to list<T>::iterator it = begin(); advance(it, sz); erase(it, end());. If size() < sz, appends sz - size()
default constructedvalue initialized elements to the sequence.
Section: 23.6 [container.adaptors] Status: Open Submitter: DIN Opened: 2010-08-25 Last modified: 2011-02-21
View all other issues in [container.adaptors].
View all issues with Open status.
Duplicate of: 1350
Discussion:
Addresses DE-22, CH-15
With the final acceptance of move operations as special members and introduction of corresponding suppression rules of implicitly generated copy operations the some library types that were copyable in C++03 are no longer copyable (only movable) in C++03, among them queue, priority_queue, and stack.
[ 2010-10-26: Daniel comments: ]
Accepting n3112 should fix this.
[2011-02-17: Lawrence comments:]
The only open issue in CH 15 with respect to the concurrency group was the treatment of atomic_future. Since we removed atomic_future in Batavia, I think all that remains is to remove the open issue from N3112 and adopt it.
Proposed resolution:
See n3112
Section: 26.5.4.2 [rand.adapt.disc] Status: Ready Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-21
View all other issues in [rand.adapt.disc].
View all issues with Ready status.
Discussion:
Addresses US-126
Each adaptor has a member function called base() which has no definition.
[ Resolution proposed by ballot comment: ]
Give it the obvious definition.
[ 2010-11-03 Daniel comments and provides a proposed resolution: ]
The following proposal adds noexcept specifiers to the declarations of the base() functions as replacement for a "Throws: Nothing" element.
[ 2010 Batavia: The working group reviewed this issue, and recommended to add the following to the Proposed Resolution. ]
After further review, the working group concurred with the Proposed Resolution.
[Batavia: waiting for WEB to review wording]
Proposed resolution:
A random number engine adaptor (commonly shortened to adaptor) a of type A is a random number engine that takes values produced by some other random number engine, and applies an algorithm to those values in order to deliver a sequence of values with different randomness properties. An engine b of type B adapted in this way is termed a base engine in this context. The expression a.base() shall be valid and shall return a const reference to a's base engine.
// property functions const Engine& base() const noexcept;
const Engine& base() const noexcept;? Returns: e.
// property functions const Engine& base() const noexcept;
const Engine& base() const noexcept;? Returns: e.
// property functions const Engine& base() const noexcept;
const Engine& base() const noexcept;? Returns: e.
Section: 27.8.2.3 [stringbuf.members] Status: Open Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View all issues with Open status.
Discussion:
Addresses GB-124
N3092 27.8.2.3 [stringbuf.members] contains this text specifying the postconditions of basic_stringbuf::str(basic_string):
Postconditions: If mode & ios_base::out is true, pbase() points to the first underlying character and epptr() >= pbase() + s.size() holds; in addition, if mode & ios_base::in is true, pptr() == pbase() + s.data() holds, otherwise pptr() == pbase() is true. [...]
Firstly, there's a simple mistake: It should be pbase() + s.length(), not pbase() + s.data().
Secondly, it doesn't match existing implementations. As far as I can tell, GCC 4.5 does not test for mode & ios_base::in in the second part of that sentence, but for mode & (ios_base::app | ios_base_ate), and Visual C++ 9 for mode & ios_base::app. Besides, the wording of the C++0x draft doesn't make any sense to me. I suggest changing the second part of the sentence to one of the following:
Replace ios_base::in with (ios_base::ate | ios_base::app), but this would require Visual C++ to change (replacing only with ios_base::ate would require GCC to change, and would make ios_base::app completely useless with stringstreams):
in addition, if mode & (ios_base::ate | ios_base::app) is true, pptr() == pbase() + s.length() holds, otherwise pptr() == pbase() is true.
Leave pptr() unspecified if mode & ios_base::app, but not mode & ios_base::ate (implementations already differ in this case, and it is always possible to use ios_base::ate to get the effect of appending, so it is not necessary to require any implementation to change):
in addition, if mode & ios_base::ate is true, pptr() == pbase() + s.length() holds, if neither mode & ios_base::ate nor mode & ios_base::app is true, pptr() == pbase() holds, otherwise pptr() >= pbase() && pptr() <= pbase() + s.length() (which of the values in this range is unspecified).
Slightly stricter:
in addition, if mode & ios_base::ate is true, pptr() == pbase() + s.length() holds, if neither mode & ios_base::ate nor mode & ios_base::app is true, pptr() == pbase() holds, otherwise pptr() == pbase() || pptr() == pbase() + s.length() (which of these two values is unspecified). A small table might help to better explain the three cases. BTW, at the end of the postconditions is this text: "egptr() == eback() + s.size() hold". Is there a perference for basic_string::length or basic_string::size? It doesn't really matter, but it looks a bit inconsistent.
Proposed resolution:
Section: 28.5.2 [re.matchflag] Status: Deferred Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View all issues with Deferred status.
Discussion:
Addresses GB-127
The Bitmask Type requirements in 17.5.2.1.3 [bitmask.types] p.3 say that all elements on a bitmask type have distinct values, but 28.5.2 [re.matchflag] defines regex_constants::match_default and regex_constants::format_default as elements of the bitmask type regex_constants::match_flag_type, both with value 0. This is a contradiction.
[ Resolution proposed by ballot comment: ]
One of the bitmask elements should be removed from the declaration and should be defined separately, in the same manner as ios_base::adjustfield, ios_base::basefield and ios_base::floatfield are defined by 27.5.3.1.2 [ios::fmtflags] p.2 and Table 120. These are constants of a bitmask type, but are not distinct elements, they have more than one value set in the bitmask. regex_constants::format_default should be specified as a constant with the same value as regex_constants::match_default.
[ 2010-10-31 Daniel comments: ]
Strictly speaking, a bitmask type cannot have any element of value 0 at all, because any such value would contradict the requirement expressed in 17.5.2.1.3 [bitmask.types] p. 3:
for any pair Ci and Cj, Ci & Ci is nonzero
So, actually both regex_constants::match_default and regex_constants::format_default are only constants of the type regex_constants::match_flag_type, and no bitmask elements.
[ 2010-11-03 Daniel comments and provides a proposed resolution: ]
The proposed resolution is written against N3126 and considered as a further improvement of the fixes suggested by n3110.
Proposed resolution:
Add the following sentence to 28.5.2 [re.matchflag] paragraph 1:
1 The type regex_constants::match_flag_type is an implementation-defined bitmask type (17.5.2.1.3). Matching a regular expression against a sequence of characters [first,last) proceeds according to the rules of the grammar specified for the regular expression object, modified according to the effects listed in Table 136 for any bitmask elements set. Type regex_constants::match_flag_type also defines the constants regex_constants::match_default and regex_constants::format_default.
Section: 28.10.4 [re.results.acc] Status: Open Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View all other issues in [re.results.acc].
View all issues with Open status.
Discussion:
Addresses GB-125
The term "target sequence" is not defined (28.10.4 [re.results.acc] p. 2).
[ Resolution proposed by ballot comment: ]
Replace "target sequence" with "string being searched/matched"
[ 2010-11-01 Daniel comments: ]
The proposed resolution looks incomplete to me, there are more normative usages of the term target sequence in clause 28, e.g. 28.12.2 [re.tokiter] p. 7.
Proposed resolution:
Wording changes are against N3126. They are intended not to conflict with the wording changes suggested by n3158.
Change 28.10.4 [re.results.acc] p. 2 as indicated:
difference_type position(size_type sub = 0) const;2 Returns: The distance from the start of the
target sequencestring being matched to (*this)[sub].first.
Section: 29 [atomics] Status: Tentatively Ready Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [atomics].
View all other issues in [atomics].
View all issues with Tentatively Ready status.
Discussion:
Addresses GB-129
Table 143 lists the typedefs for various atomic types corresponding to the various standard integer typedefs, such as atomic_int_least8_t for int_least8_t, and atomic_uint_fast64_t for uint_fast64_t. However, there are no atomic typedefs corresponding to the fixed-size standard typedefs int8_t, int16_t, and so forth.
[ 2010-10-24 Daniel adds: ]
Accepting n3164 would solve this issue.
[ 2011-02-15 Anthony corrects numbering/naming for N3225, Howard suggests improvement for the position of '(optional)', Daniel reorders rows in harmony to remaining entries and suggests specific optionality comments: ]
[2011-02-16 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
Add the following entries to table 143:
Table 146 — atomic <inttypes.h> typedefs Atomic typedef <inttypes.h> type ... ... atomic_intmax_t intmax_t atomic_uintmax_t uintmax_t atomic_int8_t // iff int8_t is provided int8_t atomic_uint8_t // iff uint8_t is provided uint8_t atomic_int16_t // iff int16_t is provided int16_t atomic_uint16_t // iff uint16_t is provided uint16_t atomic_int32_t // iff int32_t is provided int32_t atomic_uint32_t // iff uint32_t is provided uint32_t atomic_int64_t // iff int64_t is provided int64_t atomic_uint64_t // iff uint64_t is provided uint64_t
Section: 29.2 [atomics.syn] Status: Tentatively Ready Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-25
View all issues with Tentatively Ready status.
Discussion:
Addresses GB-130
The synopsis for the <atomic> header lists the macros ATOMIC_INTEGRAL_LOCK_FREE and ATOMIC_ADDRESS_LOCK_FREE.
The ATOMIC_INTEGRAL_LOCK_FREE macro has been replaced with a set of macros for each integral type, as listed in 29.4 [atomics.lockfree].
[Proposed resolution as of comment]
Against FCD, N3092:
In [atomics.syn], header <atomic> synopsis replace as indicated:
// 29.4, lock-free property#define ATOMIC_INTEGRAL_LOCK_FREE unspecified#define ATOMIC_CHAR_LOCK_FREE implementation-defined #define ATOMIC_CHAR16_T_LOCK_FREE implementation-defined #define ATOMIC_CHAR32_T_LOCK_FREE implementation-defined #define ATOMIC_WCHAR_T_LOCK_FREE implementation-defined #define ATOMIC_SHORT_LOCK_FREE implementation-defined #define ATOMIC_INT_LOCK_FREE implementation-defined #define ATOMIC_LONG_LOCK_FREE implementation-defined #define ATOMIC_LLONG_LOCK_FREE implementation-defined #define ATOMIC_ADDRESS_LOCK_FREE unspecified
[ 2010-10-26: Daniel adds: ]
The proposed resolution below is against the FCD working draft. After application of the editorial issues US-144 and US-146 the remaining difference against the working draft is the usage of implementation-defined instead of unspecified, effectively resulting in this delta:
// 29.4, lock-free property #define ATOMIC_CHAR_LOCK_FREEunspecifiedimplementation-defined #define ATOMIC_CHAR16_T_LOCK_FREEunspecifiedimplementation-defined #define ATOMIC_CHAR32_T_LOCK_FREEunspecifiedimplementation-defined #define ATOMIC_WCHAR_T_LOCK_FREEunspecifiedimplementation-defined #define ATOMIC_SHORT_LOCK_FREEunspecifiedimplementation-defined #define ATOMIC_INT_LOCK_FREEunspecifiedimplementation-defined #define ATOMIC_LONG_LOCK_FREEunspecifiedimplementation-defined #define ATOMIC_LLONG_LOCK_FREEunspecifiedimplementation-defined #define ATOMIC_ADDRESS_LOCK_FREE unspecified
It is my understanding that the intended wording should be unspecified as for ATOMIC_ADDRESS_LOCK_FREE but if this is right, we need to use the same wording in 29.4 [atomics.lockfree], which consequently uses the term implementation-defined. I recommend to keep 29.2 [atomics.syn] as it currently is and to fix 29.4 [atomics.lockfree] instead as indicated:
[2011-02-24 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
[2011-02-20: Daniel adapts the proposed wording to N3225 and fixes an editorial omission of applying N3193]
Proposed resolution:
Change 29.4 [atomics.lockfree] as indicated (The removal of the ATOMIC_ADDRESS_LOCK_FREE is an editorial step, because that macro was removed when N3193 was accepted during the Batavia meeting):
#define ATOMIC_CHAR_LOCK_FREEimplementation-definedunspecified #define ATOMIC_CHAR16_T_LOCK_FREEimplementation-definedunspecified #define ATOMIC_CHAR32_T_LOCK_FREEimplementation-definedunspecified #define ATOMIC_WCHAR_T_LOCK_FREEimplementation-definedunspecified #define ATOMIC_SHORT_LOCK_FREEimplementation-definedunspecified #define ATOMIC_INT_LOCK_FREEimplementation-definedunspecified #define ATOMIC_LONG_LOCK_FREEimplementation-definedunspecified #define ATOMIC_LLONG_LOCK_FREEimplementation-definedunspecified#define ATOMIC_ADDRESS_LOCK_FREE implementation-defined
Section: 29.3 [atomics.order] Status: Open Submitter: Canada Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [atomics.order].
View all other issues in [atomics.order].
View all issues with Open status.
Duplicate of: 1458
Discussion:
Addresses CA-21, GB-131
29.4 [atomics.lockfree] p.8 states:
An atomic store shall only store a value that has been computed from constants and program input values by a finite sequence of program evaluations, such that each evaluation observes the values of variables as computed by the last prior assignment in the sequence.
... but 1.9 [intro.execution] p.13 states:
If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [ Note: The execution of unsequenced evaluations can overlap. — end note ]
Overlapping executions can make it impossible to construct the sequence described in 29.4 [atomics.lockfree] p.8. We are not sure of the intention here and do not offer a suggestion for change, but note that 29.4 [atomics.lockfree] p.8 is the condition that prevents out-of-thin-air reads.
For an example, suppose we have a function invocation f(e1,e2). The evaluations of e1 and e2 can overlap. Suppose that the evaluation of e1 writes y and reads x whereas the evaluation of e2 reads y and writes x, with reads-from edges as below (all this is within a single thread).
e1 e2 Wrlx y-- --Wrlx x rf\ /rf X / \ Rrlx x<- ->Rrlx y
This seems like it should be allowed, but there seems to be no way to produce a sequence of evaluations with the property above.
In more detail, here the two evaluations, e1 and e2, are being executed as the arguments of a function and are consequently not sequenced-before each other. In practice we'd expect that they could overlap (as allowed by 1.9 [intro.execution] p.13), with the two writes taking effect before the two reads. However, if we have to construct a linear order of evaluations, as in 29.4 [atomics.lockfree] p.8, then the execution above is not permited. Is that really intended?
[ Resolution proposed by ballot comment ]
Please clarify.
Proposed resolution:
Section: 29.4 [atomics.lockfree] Status: Open Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-21
View all other issues in [atomics.lockfree].
View all issues with Open status.
Discussion:
Addresses US-154
There is no ATOMIC_BOOL_LOCK_FREE macro.
Proposed resolution:
Add ATOMIC_BOOL_LOCK_FREE to 29.4 [atomics.lockfree] and to 29.2 [atomics.syn]:
[..] #define ATOMIC_BOOL_LOCK_FREE unspecified #define ATOMIC_CHAR_LOCK_FREE unspecified #define ATOMIC_CHAR16_T_LOCK_FREE unspecified #define ATOMIC_CHAR32_T_LOCK_FREE unspecified [..]
Section: 29 [atomics] Status: Open Submitter: Canada Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [atomics].
View all other issues in [atomics].
View all issues with Open status.
Discussion:
Addresses CA-1
All ATOMIC_... macros should be prefixed with STD_ as in STD_ATOMIC_... to indicate they are STD macros as other standard macros. The rationale that they all seem too long seems weak.
Proposed resolution:
Change sub-clause 29.2 [atomics.syn] as indicated:
[..] // 29.4, lock-free property #define STD_ATOMIC_CHAR_LOCK_FREE unspecified #define STD_ATOMIC_CHAR16_T_LOCK_FREE unspecified #define STD_ATOMIC_CHAR32_T_LOCK_FREE unspecified #define STD_ATOMIC_WCHAR_T_LOCK_FREE unspecified #define STD_ATOMIC_SHORT_LOCK_FREE unspecified #define STD_ATOMIC_INT_LOCK_FREE unspecified #define STD_ATOMIC_LONG_LOCK_FREE unspecified #define STD_ATOMIC_LLONG_LOCK_FREE unspecified #define STD_ATOMIC_ADDRESS_LOCK_FREE unspecified // 29.6, operations on atomic types #define STD_ATOMIC_VAR_INIT(value) see below [..]
Change 29.4 [atomics.lockfree] p. 1 as indicated:
#define STD_ATOMIC_CHAR_LOCK_FREE implementation-defined #define STD_ATOMIC_CHAR16_T_LOCK_FREE implementation-defined #define STD_ATOMIC_CHAR32_T_LOCK_FREE implementation-defined #define STD_ATOMIC_WCHAR_T_LOCK_FREE implementation-defined #define STD_ATOMIC_SHORT_LOCK_FREE implementation-defined #define STD_ATOMIC_INT_LOCK_FREE implementation-defined #define STD_ATOMIC_LONG_LOCK_FREE implementation-defined #define STD_ATOMIC_LLONG_LOCK_FREE implementation-defined #define STD_ATOMIC_ADDRESS_LOCK_FREE implementation-defined1 The STD_ATOMIC_..._LOCK_FREE macros indicate the lock-free property of the corresponding atomic types, [..]
Change 29.6 [atomics.types.operations] p. 5 as indicated:
#define STD_ATOMIC_VAR_INIT(value) see below5 Remarks: A macro that expands to a token sequence suitable for initializing an atomic variable of a type that is initializion-compatible with value. Concurrent access to the variable being initialized, even via an atomic operation, constitutes a data race. [ Example:
atomic_int v = STD_ATOMIC_VAR_INIT(5);— end example ]
Change 29.7 [atomics.flag] p. 1+4 as indicated:
namespace std { [..] #define STD_ATOMIC_FLAG_INIT see below }[..] 4 The macro STD_ATOMIC_FLAG_INIT shall be defined in such a way that it can be used to initialize an object of type atomic_flag to the clear state. For a static-duration object, that initialization shall be static. It is unspecified whether an unitialized atomic_flag object has an initial state of set or clear. [ Example:
atomic_flag guard = STD_ATOMIC_FLAG_INIT;— end example ]
Section: 29.6.5 [atomics.types.operations.req] Status: Tentatively Ready Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-25
View all issues with Tentatively Ready status.
Duplicate of: 1470, 1475, 1476, 1477
Discussion:
Addresses US-175, US-165, CH-23, GB-135
29.6.5 [atomics.types.operations.req] p. 25: The first sentence is grammatically incorrect.
[ 2010-10-28 Daniel adds: ]
Duplicate issue 1475 also has a proposed resolution, but both issues are resolved with below proposed resolution.
[ 2011-02-15 Howard fixes numbering, Hans improves the wording ]
[2011-02-24 Reflector discussion]
Moved to Tentatively Ready after 6 votes.
Proposed resolution:
Change 29.6.5 [atomics.types.operations.req] p. 23 as indicated:
[ Note: For example, t
The effect ofthe compare-and-exchange operationsatomic_compare_exchange_strong isif (memcmp(object, expected, sizeof(*object)) == 0) memcpy(object, &desired, sizeof(*object)); else memcpy(expected, object, sizeof(*object));— end note ] [..]
Change 29.6.5 [atomics.types.operations.req] p. 25 as indicated:
25 Remark:
When a compare-and-exchange is in a loop, the weak version will yield better performance on some platforms. When a weak compare-and-exchange would require a loop and a strong one would not, the strong one is preferable. — end note ]The weak compare-and-exchange operations may fail spuriously, that is, return false while leaving the contents of memory pointed to by expected before the operation is the same that same as that of the object and the same as that of expected after the operationA weak compare-and-exchange operation may fail spuriously. That is, even when the contents of memory referred to by expected and object are equal, it may return false and store back to expected the same memory contents that were originally there.. [ Note: This spurious failure enables implementation of compare-and-exchange on a broader class of machines, e.g., loadlocked store-conditional machines. A consequence of spurious failure is that nearly all uses of weak compare-and-exchange will be in a loop.
Section: 29.6 [atomics.types.operations] Status: Open Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-28
View all other issues in [atomics.types.operations].
View all issues with Open status.
Discussion:
Addresses GB-136
GB requests normative clarification in 29.6 [atomics.types.operations] p.4 that concurrent access constitutes a race, as already done on p.6 and p.7.
[ Resolution proposed in ballot comment: ]
Initialisation of atomics:
We believe the intent is that for any atomics there is a distinguished initialisation write, but that this need not happens-before all the other operations on that atomic - specifically so that the initialisation write might be non-atomic and hence give rise to a data race, and hence undefined behaviour, in examples such as this (from Hans):atomic<atomic<int> *> p f() | { atomic<int>x; | W_na x p.store(&x,mo_rlx); | W_rlx p=&x } |(where na is nonatomic and rlx is relaxed). We suspect also that no other mixed atomic/nonatomic access to the same location is intended to be permitted. Either way, a note would probably help.
[2011-02-26: Hans comments and drafts wording]
I think the important point here is to clarify that races on atomics are possible, and can be introduced as a result of non-atomic initialization operations. There are other parts of this that remain unclear to me, such as whether there are other ways to introduce data races on atomics, or whether the races with initialization also introduce undefined behavior by the 3.8 lifetime rules. But I don't think that it is necessary to resolve those issues before releasing the standard. That's particularly true since we've introduced atomic_init, which allows easier ways to construct initialization races.
Proposed resolution:
Update 29.6.5 [atomics.types.operations.req] p. 5 as follows:
constexpr A::A(C desired);5 Effects: Initializes the object with the value desired.
[ Note: Construction is not atomic. — end note ]Initialization is not an atomic operation (1.10) [intro.multithread]. [Note: It is possible to have an access to an atomic object A race with its construction, for example by communicating the address of the just-constructed object A to another thread viamemory_order_relaxed
atomic operations on a suitable atomic pointer variable, and then immediately accessing A in the receiving thread. This results in undefined behavior. — end note]
In response to the editor comment to 29.6.5 [atomics.types.operations.req] p. 8: The first Effects element is the correct and intended one:
void atomic_init(volatile A *object, C desired); void atomic_init(A *object, C desired);8 Effects: Non-atomically initializes *object with value desired. This function shall only be applied to objects that have been default constructed, and then only once. [ Note: these semantics ensure compatibility with C. — end note ] [ Note: Concurrent access from another thread, even via an atomic operation, constitutes a data race. — end note ]
[Editor's note: The preceding text is from the WD as amended by N3196. N3193 makes different changes, marked up in the paper as follows:] Effects: Dynamically initializes an atomic variable. Non-atomically That is, non-atomically assigns the value desired to *object. [ Note: this operation may need to initialize locks. — end note ] Concurrent access from another thread, even via an atomic operation, constitutes a data race.
Section: 29.8 [atomics.fences] Status: Tentatively Ready Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [atomics.fences].
View all other issues in [atomics.fences].
View all issues with Tentatively Ready status.
Discussion:
Addresses US-179
The fence functions (29.8 [atomics.fences] p.5 + p.6) should be extern "C", for C compatibility.
[2011-02-16 Reflector discussion]
Moved to Tentatively Ready after 6 votes.
Proposed resolution:
namespace std { [..] // 29.8, fences extern "C" void atomic_thread_fence(memory_order); extern "C" void atomic_signal_fence(memory_order); }
Change 29.8 [atomics.fences], p. 5 and p. 6 as indicated:
extern "C" void atomic_thread_fence(memory_order);5 Effects: depending on the value of order, this operation: [..]
extern "C" void atomic_signal_fence(memory_order);6 Effects: equivalent to atomic_thread_fence(order), except that synchronizes with relationships are established only between a thread and a signal handler executed in the same thread.
Section: 29.8 [atomics.fences] Status: Tentatively Ready Submitter: BSI Opened: 2010-08-25 Last modified: 2011-02-28
View other active issues in [atomics.fences].
View all other issues in [atomics.fences].
View all issues with Tentatively Ready status.
Discussion:
Addresses GB-137
Thread fence not only establish synchronizes with relationships, there are semantics of fences that are expressed not in terms of synchronizes with relationships (for example see 29.3 [atomics.order] p.5). These semantics also need to apply to the use of atomic_signal_fence in a restricted way.
[Batavia: Concurrency group discussed issue, and is OK with the proposed resolution.]
[2011-02-26 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
Change 29.8 [atomics.fences] p. 6 as indicated:
void atomic_signal_fence(memory_order);6 Effects: equivalent to atomic_thread_fence(order), except that
synchronizes with relationshipsthe resulting ordering constraints are established only between a thread and a signal handler executed in the same thread.
Section: 30.3.1.1 [thread.thread.id] Status: Tentatively NAD Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-21
View all other issues in [thread.thread.id].
View all issues with Tentatively NAD status.
Discussion:
Addresses US-184
It is unclear when a thread::id ceases to be meaningful. The sentence "The library may reuse the value of a thread::id of a terminated thread that can no longer be joined." implies that some terminated threads can be joined. It says nothing about detached threads.
[ Resolution proposed by ballot comment: ]
Require a unique thread::id for every thread that is (1) detached and not terminated or (2) has an associated std::thread object.
[ 2010-11-22 Howard Hinnant observes ]
A thread can either be running or terminated. Additionally a thread can be joined, detached, or neither. These combine into the five possible states shown in this table:
Running | Terminated | |
---|---|---|
Neither joined nor detached | shall not reuse id | shall not reuse id |
detached | shall not reuse id | may reuse id |
joined | impossible state | may reuse id |
Only if a thread is neither joined nor detached can it be joined. Or said differently, if a thread has already been joined or detached, then it can not be joined. The sentence:
The library may reuse the value of a thread::id of a terminated thread that can no longer be joined.
precisely defines the two states shown in the above table where a thread::id may be reused.
The following program illustrates all of the possibilities:
#include <mutex> #include <thread> #include <iostream> #include <chrono> std::mutex mut; void f() { std::lock_guard<std::mutex> _(mut); std::cout << "f id = " << std::this_thread::get_id() << " terminating\n"; } void g() { std::lock_guard<std::mutex> _(mut); std::cout << "g id = " << std::this_thread::get_id() << " terminating\n"; } int main() { std::cout << "main id = " << std::this_thread::get_id() << "\n"; std::thread t1(f); std::thread(g).detach(); std::this_thread::sleep_for(std::chrono::seconds(1)); std::cout << "g's thread::id can be reused here because g has terminated and is detached.\n"; std::cout << "f's thread::id can't be reused here because f has terminated but is still joinable.\n"; std::cout << "f id = " << t1.get_id() << "\n"; t1.join(); std::cout << "f's thread::id can be reused here because f has terminated and is joined.\n"; std::cout << "f id = " << t1.get_id() << "\n"; } main id = 0x7fff71197ca0 f id = 0x100381000 terminating g id = 0x100581000 terminating g's thread::id can be reused here because g has terminated and is detached. f's thread::id can't be reused here because f has terminated but is still joinable. f id = 0x100381000 f's thread::id can be reused here because f has terminated and is joined. f id = 0x0
[2011-02-11 Reflector discussion]
Moved to Tentatively NAD after 5 votes.
Proposed resolution:
Section: 30.3.2 [thread.thread.this] Status: Tentatively NAD Submitter: Switzerland Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [thread.thread.this].
View all other issues in [thread.thread.this].
View all issues with Tentatively NAD status.
Discussion:
Addresses CH-24
What would be the value this_thread::get_id() when called from a detached thread?
[ Resolution proposed by ballot comment: ]
Add some text to clarify that get_id() still returns the same value even after detaching.
[ 2010-11-22 Howard Hinnant observes ]
30.3.2 [thread.thread.this]/1 contains the following sentence describing this_thread::get_id():
... No other thread of execution shall have this id and this thread of execution shall always have this id.
I don't object to adding "even if detached" to this sentence, but it seems unnecessary to me. "Always" means always.
[2011-02-11 Reflector discussion]
Moved to Tentatively NAD after 5 votes.
Proposed resolution:
Section: 30.3.2 [thread.thread.this] Status: Open Submitter: Switzerland Opened: 2010-08-25 Last modified: 2011-02-28
View other active issues in [thread.thread.this].
View all other issues in [thread.thread.this].
View all issues with Open status.
Discussion:
Addresses CH-25
Clock related operations are currently not required not to throw. So "Throws: Nothing." is not always true.
[ Resolution proposed by ballot comment: ]
Either require clock related operations not to throw (in 20.10) or change the Throws clauses in 30.3.2. Also possibly add a note that abs_time in the past or negative rel_time is allowed.
[2011-02-10: Howard Hinnant provides a resolution proposal]
[Previous proposed resolution:]
Change the Operational semantics of C1::now() in 20.11.3 [time.clock.req], Table 59 — Clock requirements as follows:
Table 59 — Clock requirements Expression Return type Operational semantics C1::now() C1::time_point Returns a time_point object
representing the current point in time.
Shall not throw an exception.
[2011-02-19: Daniel comments and suggests an alternative wording]
Imposing the no-throw requirement on C1::now() of any clock time is an overly radical step: It has the indirect consequences that representation types for C1::rep can never by types with dynamic memory managment, e.g. my big_int, which are currently fully supported by the time utilities. Further-on this strong constraint does not even solve the problem described in the issue, because we are still left with the fact that any of the arithmetic operations of C1::rep, C1::duration, and C1::time_point may throw exceptions.
The alternative proposal uses the following strategy: The general Clock requirements remain untouched, but we require that any functions of the library-provided clocks from sub-clause 20.11.7 [time.clock] and their associated types shall not throw exceptions. Second, we replace existing noexcept specifications of functions from Clause 30 that depend on durations, clocks, or time points by wording that clarifies that these functions can only throw, if the operations of user-provided durations, clocks, or time points used as arguments to these functions throw exceptions.
Proposed resolution:
Add the following new requirement set at the end of sub-clause 20.11.3 [time.clock.req]: [Comment: This requirement set is intentionally incomplete. The reason for this incompleteness is the based on the fact, that if we would make it right for C++0x, we would end up defining something like a complete ArithmeticLike concept for TC::rep, TC::duration, and TC::time_point. But this looks out-of scope for C++0x to me. The effect is that we essentially do not exactly say, which arithmetic or comparison operations can be used in the time-dependent functions from Clause 30, even though I expect that all declared functions of duration and time_point are well-formed and well-defined. — end comment]
3 [ Note: the relative difference in durations between those reported by a given clock and the SI definition is a measure of the quality of implementation. — end note ]
? A type TC meets the TrivialClock requirements if:
TC satisfies the Clock requirements (20.11.3 [time.clock.req]),
the types TC::rep, TC::duration, and TC::time_point satisfy the requirements of EqualityComparable ( [equalitycomparable]), LessThanComparable ( [lessthancomparable]), DefaultConstructible ( [defaultconstructible]), CopyConstructible ( [copyconstructible]), CopyAssignable ( [copyassignable]), Destructible ( [destructible]), and of numeric types ([numeric.requirements]) [Note: This means in particular, that operations of these types will not throw exceptions — end note ],
lvalues of the types TC::rep, TC::duration, and TC::time_point are swappable (17.6.3.2 [swappable.requirements]),
the function TC::now() does not throw exceptions, and
the type TC::time_point::clock does meet the TrivialClock requirements, recursively.
Modify 20.11.7 [time.clock] p. 1 as follows:
1 - The types defined in this subclause shall satisfy the TrivialClock requirements (20.11.1).
Modify 20.11.7.1 [time.clock.system] p. 1, class system_clock synopsis, as follows:
class system_clock { public: typedef see below rep; typedef ratio<unspecified , unspecified > period; typedef chrono::duration<rep, period> duration; typedef chrono::time_point<system_clock> time_point; static const bool is_monotonic is_steady = unspecified; static time_point now() noexcept; // Map to C API static time_t to_time_t (const time_point& t) noexcept; static time_point from_time_t(time_t t) noexcept; };
Modify the prototype declarations in 20.11.7.1 [time.clock.system] p. 3 + p. 4 as indicated (This edit also fixes the miss of the static specifier in these prototype declarations):
static time_t to_time_t(const time_point& t) noexcept;3 - [...]
static time_point from_time_t(time_t t) noexcept;4 - [...]
Modify 20.11.7.2 [time.clock.steady] p. 1, class steady_clock synopsis, as follows:
class steady_clock { public: typedef unspecified rep; typedef ratio<unspecified , unspecified > period; typedef chrono::duration<rep, period> duration; typedef chrono::time_point<unspecified, duration> time_point; static const bool is_monotonic is_steady = true; static time_point now() noexcept; };
Modify 20.11.7.3 [time.clock.hires] p. 1, class high_resolution_clock synopsis, as follows:
class high_resolution_clock { public: typedef unspecified rep; typedef ratio<unspecified , unspecified > period; typedef chrono::duration<rep, period> duration; typedef chrono::time_point<unspecified, duration> time_point; static const bool is_monotonic is_steady = unspecified; static time_point now() noexcept; };
Add a new paragraph at the end of 30.2.4 [thread.req.timing]:
6 The resolution of timing provided by an implementation depends on both operating system and hardware. The finest resolution provided by an implementation is called the native resolution.
? Implementation-provided clocks that are used for these functions shall meet the TrivialClock requirements (20.11.3 [time.clock.req]).
Edit the synopsis of 30.3.2 [thread.thread.this] before p. 1:
template <class Clock, class Duration> void sleep_until(const chrono::time_point<Clock, Duration>& abs_time)noexcept; template <class Rep, class Period> void sleep_for(const chrono::duration<Rep, Period>& rel_time)noexcept;
Modify the prototype specifications in 30.3.2 [thread.thread.this] before p. 4 and p. 6 and re-add a Throws element following the Synchronization elements at p. 5 and p. 7:
template <class Clock, class Duration> void sleep_until(const chrono::time_point<Clock, Duration>& abs_time)noexcept;4 - [...]
5 - Synchronization: None. ? - Throws: Nothing unless an exception is thrown by Clock::now() or by an operation of abs_time. [Note: Instantiations of time point types and clocks supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note]
template <class Rep, class Period> void sleep_for(const chrono::duration<Rep, Period>& rel_time)noexcept;6 [...]
7 Synchronization: None. ? Throws: Nothing unless an exception is thrown by an operation of rel_time. [Note: Instantiations of duration types supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note]
Modify the Throws elements of 30.4.1.3 [thread.timedmutex.requirements] p. 9 and p. 16 as indicated and modify the Effects elements p. 5 and p. 12 to clarify the lock state in the presence of exceptions. Note that the edit also fixes a minor incorrectness in p. 5: Duration types need to compare against duration<>::zero(), not 0:
3 The expression m.try_lock_for(rel_time) shall be well-formed and have the following semantics:
[...] 5 Effects: The function attempts to obtain ownership of the mutex within the relative timeout (30.2.4) specified by rel_time. If the time specified by rel_time is less than or equal to0rel_time.zero(), the function attempts to obtain ownership without blocking (as if by calling try_lock()). The function shall return within the timeout specified by rel_time only if it has obtained ownership of the mutex object or an exception is thrown. If an exception is thrown then a lock shall not have been acquired for the current execution agent. [ Note: As with try_lock(), there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. — end note ] [...] 9 Throws: Nothing unless an exception is thrown by an operation of rel_time. [Note: Instantiations of duration types supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note]. 10 The expression m.try_lock_until(abs_time) shall be well-formed and have the following semantics: [...] 12 Effects: The function attempts to obtain ownership of the mutex. If abs_time has already passed, the function attempts to obtain ownership without blocking (as if by calling try_lock()). The function shall return before the absolute timeout (30.2.4) specified by abs_time only if it has obtained ownership of the mutex object or an exception is thrown. If an exception is thrown then a lock shall not have been acquired for the current execution agent. [ Note: As with try_lock(), there is no guarantee that ownership will be obtained if the lock is available, but implementations are expected to make a strong effort to do so. — end note ] [...] 16 Throws: Nothing unless an exception is thrown by the now() function of the used clock or by an operation of abs_time. [Note: Instantiations of time point types and clocks supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note].
Modify the class timed_mutex synopsis in 30.4.1.3.1 [thread.timedmutex.class] as indicated:
class timed_mutex { public: [...] template <class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)noexcept; template <class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)noexcept; [...] };
Modify the class recursive_timed_mutex synopsis in 30.4.1.3.2 [thread.timedmutex.recursive] as indicated:
class recursive_timed_mutex { public: [...] template <class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)noexcept; template <class Clock, class Duration> bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)noexcept; [...] };
Modify the class template unique_lock synopsis in 30.4.2.2 [thread.lock.unique] as indicated. This edit seems also to fix an inconsistency between the timed waiting c'tors and the timed waiting member functions (see next bullet):
template <class Mutex> class unique_lock { public: [...] template <class Clock, class Duration> unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time)noexcept; template <class Rep, class Period> unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time)noexcept; [...] };
Modify the constructor prototypes in 30.4.2.2.1 [thread.lock.unique.cons] before p. 14 and p. 17 and re-add Throws elements as indicated. This edit seems also to fix an inconsistency compared to the timed waiting member functions:
template <class Clock, class Duration> unique_lock(mutex_type& m, const chrono::time_point<Clock, Duration>& abs_time)noexcept;[...]
16 Postconditions: pm == &m and owns == res, where res is the value returned by the call to m.try_lock_until(abs_time). ?? Throws: Nothing unless the exception is thrown by m.try_lock_until(abs_time).
template <class Rep, class Period> unique_lock(mutex_type& m, const chrono::duration<Rep, Period>& rel_time)noexcept;[...]
19 Postconditions: pm == &m and owns == res, where res is the value returned by the call to m.try_lock_for(rel_time). ?? Throws: Nothing unless the exception is thrown by m.try_lock_for(rel_time).
Modify the time-related Throws elements in 30.5.1 [thread.condition.condvar], p. 19, p. 25, p. 36 and add some new Throws elements as indicated. The latter are needed to honor possible exceptions from predicates [As an editorial recommendation it is suggested if issue 1497 is accepted to insert the new Throws element following [thread.condition.condvar] p. 14 in front of the added "std::system_error when an exception is required (30.2.2)" of 1497 and insert the word "Otherwise, " between these sentences. The same recommendation is given for the similar Throws element addition following [thread.condition.condvar] p. 29]:
[...]
template <class Predicate> void wait(unique_lock<mutex>& lock, Predicate pred);
14 Effects:
while (!pred()) wait(lock);
?? Throws: Any exception thrown by an operation of pred or as result of the remaining effects.
[...]
19 Throws: Any exception thrown by Clock::now() or by an operation of abs_time. [Note: Instantiations of time point types and clocks supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note] Otherwise system_error when an exception is required (30.2.2).
[...]
25 Throws: Any exception thrown by an operation of rel_time. [Note: Instantiations of duration types supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note] Otherwise system_error when an exception is required (30.2.2).
[...]
template <class Clock, class Duration, class Predicate> bool wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
27 Effects:
while (!pred()) if (wait_until(lock, abs_time) == cv_status::timeout) return pred(); return true;
28 Returns: pred()
29 [ Note: The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered. — end note ]
?? Throws: Any exception thrown by an operation of pred or as result of the remaining effects.
template <class Rep, class Period, class Predicate> bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);
[...]
31 Effects: as if
return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
[...]
36 Throws: Any exception thrown by an operation of rel_time or pred. [Note: Instantiations of duration types supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note] Otherwise system_error when an exception is required (30.2.2).
Modify the time-related Throws elements in 30.5.2 [thread.condition.condvarany], p. 15, p. 20, p. 30 and add some new Throws elements as indicated. The latter are needed to honor possible exceptions from predicates:
[...]
template <class Lock, class Predicate> void wait(Lock& lock, Predicate pred);
11 Effects:
while (!pred()) wait(lock);
?? Throws: Any exception thrown by an operation of pred or as result of the remaining effects.
[...]
15 Throws: Any exception thrown by Clock::now() or by an operation of abs_time. [Note: Instantiations of time point types and clocks supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note] Otherwise system_error when an exception is required (30.2.2).
[...]
20 Throws: Any exception thrown by an operation of rel_time. [Note: Instantiations of duration types supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note]. Otherwise system_error when an exception is required (30.2.2).
[...]
template <class Lock, class Clock, class Duration, class Predicate> bool wait_until(Lock& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
22 Effects:
while (!pred()) if (wait_until(lock, abs_time) == cv_status::timeout) return pred(); return true;
23 Returns: pred()
24 [ Note: The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered. — end note ]
?? Throws: Any exception thrown by an operation of pred or as result of the remaining effects.
template <class Lock, class Rep, class Period, class Predicate> bool wait_for(Lock& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);
25 Effects: as if
return wait_until(lock, chrono::steady_clock::now() + rel_time, std::move(pred));
[...]
30 Throws: Any exception thrown by an operation of rel_time or pred. [Note: Instantiations of duration types supplied by the implementation as specified in 20.11.7 [time.clock] do not throw exceptions. — end note] Otherwise system_error when an exception is required (30.2.2).
Section: 30.4.4.2 [thread.once.callonce] Status: Tentatively Ready Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-28
View all issues with Tentatively Ready status.
Discussion:
Addresses US-190
The term "are serialized" is never defined (30.4.4.2 [thread.once.callonce] p. 2).
[ Resolution proposed by ballot comment: ]
Remove the sentence with "are serialized" from paragraph 2. Add "Calls to call_once on the same once_flag object shall not introduce data races (17.6.4.8)." to paragraph 3.
[ 2010-11-01 Daniel translates NB comment into wording ]
[ 2011-02-17: Hans proposes an alternative resolution ]
[ 2011-02-25: Hans, Clark, and Lawrence update the suggested wording ]
[2011-02-26 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
Change 30.4.4.2 [thread.once.callonce] p.2+3 as indicated:
template<class Callable, class ...Args> void call_once(once_flag& flag, Callable&& func, Args&&... args);[..]
2 Effects:Calls to call_once on the same once_flag object are serialized. If there has been a prior effective call to call_once on the same once_flag object, the call to call_once returns without invoking func. If there has been no prior effective call to call_once on the same once_flag object, INVOKE(decay_copy( std::forward<Callable>(func)), decay_copy(std::forward<Args>(args))...) is executed. The call to call_once is effective if and only if INVOKE(decay_copy( std::forward<Callable>(func)), decay_copy(std::forward<Args>(args))...) returns without throwing an exception. If an exception is thrown it is propagated to the caller.An execution ofcall_once
that does not call itsfunc
is a passive execution. An execution ofcall_once
that calls itsfunc
is an active execution. An active execution shall callINVOKE(decay_copy(std::forward<Callable>(func)), decay_copy(std::forward<Args>(args))...)
. If such a call tofunc
throws an exception, the execution is exceptional, otherwise it is returning. An exceptional execution shall propagate the exception to the caller ofcall_once
. Among all executions ofcall_once
for any givenonce_flag
: at most one shall be a returning execution; if there is a returning execution, it shall be the last active execution; and there are passive executions only if there is a returning execution. [Note: Passive executions allow other threads to reliably observe the results produced by the earlier returning execution. — end note] 3 Synchronization:The completion of an effective call to call_once on a once_flag object synchronizes with (1.10 [intro.multithread]) all subsequent calls to call_once on the same once_flag object.For any givenonce_flag
: all active executions occur in a total order; completion of an active execution synchronizes with (1.10 [intro.multithread]) the start of the next one in this total order; and the returning execution synchronizes with the return from all passive executions.
Section: 30.5 [thread.condition] Status: Tentatively Ready Submitter: Switzerland Opened: 2010-08-25 Last modified: 2011-02-28
View all other issues in [thread.condition].
View all issues with Tentatively Ready status.
Discussion:
Addresses CH-30
If lock.lock() throws an exception, the postcondition can not be generally achieved.
[ Resolution proposed by ballot comment: ]
Either state that the postcondition might not be achieved, depending on the error condition, or state that terminate() is called in this case.
[ 2010-08-13 Peter Sommerlad comments and provides wording ]
30.5.1 [thread.condition.condvar], 30.5.2 [thread.condition.condvarany]
p. 13, last bullet, and corresponding paragraphs in all wait functions Problem:
Condition variable wait might fail, because the lock cannot be acquired when notified. CH-30 says: "If lock.lock() throws an exception, the postcondition can not be generally achieved." CH-30 proposes: "Either state that the postcondition might not be achieved, depending on the error condition, or state that terminate() is called in this case." The discussion in Rapperswil concluded that calling terminate() might be too drastic in this case and a corresponding exception should be thrown/passed on and one should use a lock type that allows querying its status, which unique_lock allows for std::condition_variable We also had some additional observations while discussing in Rapperswil:
- in 30.5.1 [thread.condition.condvar] wait with predicate and wait_until with predicate lack the precondition, postcondition and Error conditions sections. the lack of the precondition would allow to call pred() without holding the lock.
- in 30.5.1 [thread.condition.condvar] wait_until and wait_for and 30.5.2 [thread.condition.condvarany] wait_for still specify an error condition for a violated precondition. This should be removed.
and add the following proposed solution:
[2011-02-27: Daniel adapts numbering to n3225]
Proposed resolution:
void wait(unique_lock<mutex>& lock);
[..]9 Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
- no other thread is waiting on this condition_variable object or
- lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait or timed_wait) threads.
[..]11 Postcondition: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
template <class Predicate> void wait(unique_lock<mutex>& lock, Predicate pred);
?? Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
- no other thread is waiting on this condition_variable object or
- lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait or timed_wait) threads.
14 Effects:
while (!pred()) wait(lock);
?? Postcondition: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
?? Throws: std::system_error when an exception is required (30.2.2).
?? Error conditions:
- equivalent error condition from lock.lock() or lock.unlock().
template <class Clock, class Duration> cv_status wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time);
15 Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
- no other thread is waiting on this condition_variable object or
- lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait, wait_for, or wait_until) threads.
[..]
[..]17 Postcondition: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
20 Error conditions:
operation_not_permitted — if the thread does not own the lock.- equivalent error condition from lock.lock() or lock.unlock().
template <class Rep, class Period> cv_status wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time);
21 Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
- no other thread is waiting on this condition_variable object or
- lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait, wait_for, or wait_until) threads.
[..]
[..]24 Postcondition: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
26 Error conditions:
operation_not_permitted — if the thread does not own the lock.- equivalent error condition from lock.lock() or lock.unlock().
template <class Clock, class Duration, class Predicate> bool wait_until(unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred);
?? Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
- no other thread is waiting on this condition_variable object or
- lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait or timed_wait) threads.
27 Effects:
while (!pred()) if (wait_until(lock, abs_time) == cv_status::timeout) return pred(); return true;
28 Returns: pred()
?? Postcondition: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
29 [ Note: The returned value indicates whether the predicate evaluates to true regardless of whether the timeout was triggered. — end note ]
?? Throws: std::system_error when an exception is required (30.2.2).
?? Error conditions:
- equivalent error condition from lock.lock() or lock.unlock().
template <class Rep, class Period, class Predicate> bool wait_for(unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred);
30 Requires: lock.owns_lock() is true and lock.mutex() is locked by the calling thread, and either
- no other thread is waiting on this condition_variable object or
- lock.mutex() returns the same value for each of the lock arguments supplied by all concurrently waiting (via wait, wait_for, or wait_until) threads.
[..]
33 Postcondition: lock.owns_lock() is true and lock.mutex() is locked by the calling thread.
[..]
37 Error conditions:
operation_not_permitted — if the thread does not own the lock.- equivalent error condition from lock.lock() or lock.unlock().
template <class Lock, class Predicate> void wait(Lock& lock, Predicate pred);
[Note: if any of the wait functions exits with an exception it is indeterminate if the Lock is held. One can use a Lock type that allows to query that, such as the unique_lock wrapper. — end note]
11 Effects:
while (!pred()) wait(lock);
[..]
31 Error conditions:
operation_not_permitted — if the thread does not own the lock.- equivalent error condition from lock.lock() or lock.unlock().
Section: 30.6.4 [futures.state] Status: Open Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-21
View all other issues in [futures.state].
View all issues with Open status.
Discussion:
Addresses US-195
The intent and meaning of the paragraph is not apparent.
Proposed resolution:
Section: 30.6.5 [futures.promise] Status: Open Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [futures.promise].
View all other issues in [futures.promise].
View all issues with Open status.
Discussion:
Addresses US-196
The term "are serialized" is not defined (30.6.5 [futures.promise] p. 21, 25).
[ Resolution proposed by ballot comment: ]
Replace "are serialized" with "shall not introduce a data race (17.6.4.8)".
[ 2010-11-02 Daniel translates proposal into proper wording changes ]
Proposed resolution:
21 Synchronization: calls to set_value and set_exception on a single promise object
are serializedshall not introduce a data race ([res.on.data.races]). [ Note: and they synchronize and serialize with other functions through the referred associated asynchronous state. — end note ]
25 Synchronization: calls to set_value and set_exception on a single promise object
are serializedshall not introduce a data race ([res.on.data.races]). [ Note: and they synchronize and serialize with other functions through the referred associated asynchronous state. — end note ]
Section: 30.6.5 [futures.promise] Status: Open Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [futures.promise].
View all other issues in [futures.promise].
View all issues with Open status.
Discussion:
Addresses US-197
There is no defined synchronization between promise::set_value and future::get (30.6.5 [futures.promise] p. 21, 25).
[ Resolution proposed by ballot comment: ]
Replace "[Note: and they synchronize and serialize with other functions through the referred associated asynchronous state. — end note]" with the normative "They synchronize with (1.10) any operation on a future object with the same associated asynchronous state marked ready."
[ 2010-11-02 Daniel translates proposal into proper wording changes ]
Proposed resolution:
21 Synchronization: calls to set_value and set_exception on a single promise object are serialized.
[ Note: and they synchronize and serialize with other functions through the referred associated asynchronous state. — end note ]They synchronize with ([intro.multithread]) any operation on a future object with the same associated asynchronous state marked ready.
25 Synchronization: calls to set_value and set_exception on a single promise object are serialized.
[ Note: and they synchronize and serialize with other functions through the referred associated asynchronous state. — end note ]They synchronize with ([intro.multithread]) any operation on a future object with the same associated asynchronous state marked ready.
Section: 30.6.5 [futures.promise] Status: Open Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [futures.promise].
View all other issues in [futures.promise].
View all issues with Open status.
Discussion:
Addresses US-199
promise::XXX_at_thread_exit functions have no synchronization requirements. Specifying synchronization for these member functions requires coordinating with the words in 30.6.5/21 and 25, which give synchronization requirements for promise::set_value and promise::set_exception (30.6.5 [futures.promise] p. 26 ff., p. 29 ff.).
[ Resolution proposed by ballot comment: ]
Change 30.6.5/21 to mention set_value_at_thread_exit and set_exception_at_thread_exit; with this text, replace 30.6.5/25 and add two new paragraphs, after 30.6.5/28 and 30.6.5/31.
Proposed resolution:
Section: 30.6.9.1 [futures.task.members] Status: Tentatively Ready Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-21
View other active issues in [futures.task.members].
View all other issues in [futures.task.members].
View all issues with Tentatively Ready status.
Discussion:
Addresses US-207
The constructor that takes R(*)(ArgTypes...) is not needed; the constructor that takes a callable type works for this argument type. More generally, the constructors for packaged_task should parallel those for function.
[ US-207 Suggested Resolution: ]
Review the constructors for packaged_task and provide the same ones as function, except where inappropriate.
[ 2010-10-22 Howard provides wording, as requested by the LWG in Rapperswil. ]
[2011-02-10 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
Alter the list of constructors in both 30.6.9 [futures.task] and in 30.6.9.1 [futures.task.members] as indicated:
template <class F> explicit packaged_task(F f); template <class F, class Allocator> explicit packaged_task(allocator_arg_t, const Allocator& a, F f); explicit packaged_task(R(*f)(ArgTypes...));template <class F> explicit packaged_task(F&& f); template <class F, class Allocator> explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f);
Section: 30.6.9.1 [futures.task.members] Status: Tentatively Ready Submitter: INCITS Opened: 2010-08-25 Last modified: 2011-02-24
View other active issues in [futures.task.members].
View all other issues in [futures.task.members].
View all issues with Tentatively Ready status.
Discussion:
Addresses US-208
packaged_task::make_ready_at_thread_exit has no synchronization requirements.
[ Resolution proposed by ballot comment: ]
Figure out what the synchronization requirements should be and write them.
[2011-02-09 Anthony provides a proposed resolution]
[2011-02-19 Additional edits by Hans, shown in the proposed resolution section]
[2011-02-22 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
Add a new paragraph following 30.6.9.1 [futures.task.members] p. 19:
void make_ready_at_thread_exit(ArgTypes... args);
19 - ...
?? - Synchronization: Following a successful call to make_ready_at_thread_exit, the destruction of all objects with thread storage duration associated with the current thread happens before the associated asynchronous state is made ready. The marking of the associated asynchronous state as ready synchronizes with (1.10 [intro.multithread]) the successful return from any function that detects that the state is set to ready.
Section: 23.2.1 [container.requirements.general] Status: New Submitter: Mike Spertus Opened: 2010-10-16 Last modified: 2011-02-21
View other active issues in [container.requirements.general].
View all other issues in [container.requirements.general].
View all issues with New status.
Discussion:
Addresses US-104, US-141
The standard doesn't say that containers should use abstract pointer types internally. Both Howard and Pablo agree that this is the intent. Further, it is necessary for containers to be stored, for example, in shared memory with an interprocess allocator (the type of scenario that allocators are intended to support).
In spite of the (possible) agreement on intent, it is necessary to make this explicit:
An implementations may like to store the result of dereferencing the pointer (which is a raw reference) as an optimization, but that prevents the data structure from being put in shared memory, etc. In fact, a container could store raw references to the allocator, which would be a little weird but conforming as long as it has one by-value copy. Furthermore, pointers to locales, ctypes, etc. may be there, which also prevents the data structure from being put in shared memory, so we should make explicit that a container does not store raw pointers or references at all.
[ Pre-batavia ]
This issue is being opened as part of the response to NB comments US-104/141. See paper N3171 in the pre-Batavia mailing.
Proposed resolution:
Add to the end of 23.2.1 [container.requirements.general] p. 8:
[..] In all container types defined in this Clause, the member get_allocator() returns a copy of the allocator used to construct the container or, if that allocator has been replaced, a copy of the most recent replacement. The container may not store internal objects whose types are of the form T * or T & except insofar as they are part of the item type or members.
Section: 29 [atomics] Status: New Submitter: Hans Boehm Opened: 2010-11-13 Last modified: 2010-11-14
View other active issues in [atomics].
View all other issues in [atomics].
View all issues with New status.
Discussion:
Addresses GB-63 for Clause 29
Clause 29 does not specify noexcept for any of the atomic operations. It probably should, though that's not completely clear. In particular, atomics may want to throw in implementations that support transactional memory.
Proposed resolution:
Section: 5.3.4 [expr.new], 5.3.5 [expr.delete] Status: New Submitter: Hans Boehm Opened: 2011-02-26 Last modified: 2011-02-28
View all issues with New status.
Discussion:
Addresses US-34
Technical details:
When the same unit of storage is allocated and deallocated repeatedly, operations on it can't be allowed to race between the allocator and the user program. But I don't see any mention of happens-before in the descriptions of allocation and deallocation functions. Proposed resolution (not wording yet):The call to an allocation function returning a pointer P must happen-before the matching deallocation call with P as a parameter. Otherwise the behavior is undefined. I don't know whether receiving P with memory_order_consume fits this requirement. memory_order_relaxed does not.
If some memory is passed to a deallocation function, the implementation must ensure that the deallocation call happens-before any allocation call that returns the same memory address.
[2011-02-26: Hans comments and drafts wording]
The second requirement already exists, almost verbatim, as 18.6.1.4 [new.delete.dataraces] p. 1. I think this is where the statement belongs. However, this paragraph requires work to correctly address the first part of the issue.
Proposed resolution:
Change 18.6.1.4 [new.delete.dataraces] p. 1 as follows:
1
The library versions of operator new and operator delete, user replacement versions of global operator new and operator delete, and the C standard library functions calloc, malloc, realloc, and free shall not introduce data races (1.10 [intro.multithread]) as a result of concurrent calls from different threads.For purposes of determining the existence of data races, the library versions of operator new, user replacement versions of global operator new, and the C standard library functions calloc and malloc shall behave as though they accessed and modified only the storage referenced by the return value. The library versions of operator delete, user replacement versions of operator delete, and the C standard library function free shall behave as though they accessed and modified only the storage referenced by their first argument. The C standard library realloc function shall behave as though it accessed and modified only the storage referenced by its first argument and by its return value. Calls to these functions that allocate or deallocate a particular unit of storage shall occur in a single total order, and each such deallocation call shall happen before the next allocation (if any) in this order.
Section: 30.6.9.2 [futures.task.nonmembers] Status: Tentatively Ready Submitter: Howard Hinnant Opened: 2010-08-29 Last modified: 2011-02-21
View all issues with Tentatively Ready status.
Discussion:
[futures.task.nonmembers]/3 says:
template <class R, class Alloc> struct uses_allocator<packaged_task<R>, Alloc>;
This is a declaration, but should be a definition.
Proposed resolution:
Change [futures.task.nonmembers]/3:
template <class R, class Alloc> struct uses_allocator<packaged_task<R>, Alloc>;: true_type {};
Section: 28.8.3 [re.regex.assign] Status: Tentatively Ready Submitter: Volker Lukas Opened: 2010-10-21 Last modified: 2011-02-25
View all issues with Tentatively Ready status.
Discussion:
In working draft N3126, subclause 28.8.3 [re.regex.assign], paragraphs 12, 13 and 19, the name string_type is used. This is presumably a typedef for basic_string<value_type>, where value_type is the character type used by basic_regex. The basic_regex template however defines no such typedef, and neither does the <regex> header or the <initializer_list> header included by <regex>.
[ 2010-11-03 Daniel comments and suggests alternative wording: ]
The proposed resolution needs to use basic_string<charT> instead of basic_string<char>
Previous Proposed Resolution:
Make the following changes to [re.regex.assign]:basic_regex& assign(const charT* ptr, flag_type f = regex_constants::ECMAScript);12 Returns: assign(
string_typebasic_string<charT>(ptr), f).basic_regex& assign(const charT* ptr, size_t len, flag_type f = regex_constants::ECMAScript);13 Returns: assign(
string_typebasic_string<charT>(ptr, len), f).[..] template <class InputIterator> basic_regex& assign(InputIterator first, InputIterator last, flag_type f = regex_constants::ECMAScript);18 Requires: The type InputIterator shall satisfy the requirements for an Input Iterator (24.2.3).
19 Returns: assign(
string_typebasic_string<charT>(first, last), f).
[ 2010 Batavia ]
Unsure if we should just give basic_regex a string_type typedef. Looking for when string_type was introduced into regex. Howard to draft wording for typedef typename traits::string_type string_type, then move to Review.
[ 2011-02-16: Daniel comments and provides an alternative resolution. ]
I'm strongly in favour with the Batavia idea to provide a separate string_type within basic_regex, but it seems to me that the issue resultion should add one more important typedef, namely that of the traits type! Currently, basic_regex is the only template that does not publish the type of the associated traits type. Instead of opening a new issue, I added this suggestion as part of the proposed wording.
[2011-02-24 Reflector discussion]
Moved to Tentatively Ready after 6 votes.
Proposed resolution:
Change the class template basic_regex synopsis, 28.8 [re.regex] p. 3, as indicated:
namespace std { template <class charT, class traits = regex_traits<charT> > class basic_regex { public: // types: typedef charT value_type; typedef traits traits_type; typedef typename traits::string_type string_type; typedef regex_constants::syntax_option_type flag_type; typedef typename traits::locale_type locale_type; [..] }; }
Section: 21.4.1 [string.require] Status: Open Submitter: José Daniel García Sánchez Opened: 2010-10-21 Last modified: 2011-02-21
View all other issues in [string.require].
View all issues with Open status.
Discussion:
Clause 21.4.1 [string.require]p3 states:
No erase() or pop_back() member function shall throw any exceptions.
However in 21.4.6.5 [string::erase] p2 the first version of erase has
Throws: out_of_range if pos > size().
Proposed resolution:
Update [string.require]p/3:
3 No
erase() orpop_back() member function shall throw any exceptions.
Section: 20.11.5.5 [time.duration.nonmember] Status: Tentatively Ready Submitter: P.J. Plauger Opened: 2010-10-14 Last modified: 2010-11-13
View other active issues in [time.duration.nonmember].
View all other issues in [time.duration.nonmember].
View all issues with Tentatively Ready status.
Discussion:
In [time] and [time.duration.nonmember] we have:
template <class Rep1, class Period, class Rep2> duration<typename common_type<Rep1, Rep2>::type, Period> operator*(const Rep1& s, const duration<Rep2, Period>& d);
Everywhere else, we always have <rep, period> in that order for a given type. But here, we have Period and Rep2 in reverse order for <Rep2, Period>. This is probably of little importance, since the template parameters are seldom spelled out for a function like this. But changing it now will eliminate a potential source of future errors and confusion.
Proposed resolution:
Change the signature in [time] and [time.duration.nonmember] to:
template <class Rep1, classPeriodRep2, classRep2Period> duration<typename common_type<Rep1, Rep2>::type, Period> operator*(const Rep1& s, const duration<Rep2, Period>& d);
Section: 23.4.4.4 [map.modifiers], 23.4.5.3 [multimap.modifiers] Status: Open Submitter: P.J. Plauger Opened: 2010-10-14 Last modified: 2011-02-21
View all issues with Open status.
Discussion:
In [unord.map.modifiers], the signature:
template <class P> pair<iterator, bool> insert(P&& obj);
now has an added Remarks paragraph:
Remarks: This signature shall not participate in overload resolution unless P is implicitly convertible to value_type.
The same is true for unordered_multimap.
But neither map nor multimap have this constraint, even though it is a Good Thing(TM) in those cases as well.[ The submitter suggests: Add the same Remarks clause to [map.modifiers] and [multimap.modifiers]. ]
[ 2010-10-29 Daniel comments: ]
I believe both paragraphs need more cleanup: First, the current Requires element conflict with the Remark; second, it seems to me that the whole single Requires element is intended to be split into a Requires and an Effects element; third, the reference to tuple is incorrect (noticed by Paolo Carlini); fourth, it refers to some non-existing InputIterator parameter relevant for a completely different overload; sixth, the return type of the overload with hint is wrong. The following proposed resolution tries to solve these issues as well and uses similar wording as for the corresponding unordered containers. Unfortunately it has some redundancy over Table 99, but I did not remove the specification because of the more general template parameter P - the Table 99 requirements apply only for an argument identical to value_type.
Proposed resolution:template <class P> pair<iterator, bool> insert(P&& x); template <class P>pair<iterator, bool>insert(const_iterator position, P&& x);1 Requires:
P shall be convertible tovalue_type is constructible from std::forward<P>(x)..If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type,mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type.
? Effects: Inserts x converted to value_type if and only if there is no element in the container with key equivalent to the key of value_type(x). For the second form, the iterator position is a hint pointing to where the search should start. ? Returns: For the first form, the bool component of the returned pair object indicates whether the insertion took place and the iterator component - or for the second form the returned iterator - points to the element with key equivalent to the key of value_type(x). ? Complexity: Logarithmic in general, but amortized constant if x is inserted right before position. ? Remarks: These signatures shall not participate in overload resolution unless P is implicitly convertible to value_type.
template <class P> iterator insert(P&& x); template <class P> iterator insert(const_iterator position, P&& x);1 Requires:
P shall be convertible tovalue_type is constructible from std::forward<P>(x).If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type, mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type.
? Effects: Inserts x converted to value_type. For the second form, the iterator position is a hint pointing to where the search should start. ? Returns: An iterator that points to the element with key equivalent to the key of value_type(x). ? Complexity: Logarithmic in general, but amortized constant if x is inserted right before position. ? Remarks: These signatures shall not participate in overload resolution unless P is implicitly convertible to value_type.
[ 2010 Batavia: ]
We need is_convertible, not is_constructible, both in ordered and unordered containers.
Proposed resolution:
template <class P> pair<iterator, bool> insert(P&& x); template <class P> pair<iterator, bool> insert(const_iterator position, P&& x);1 Requires: P shall be convertible to value_type.
If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type,mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type. ? Remarks: These signatures shall not participate in overload resolution unless P is implicitly convertible to value_type.
template <class P> iterator insert(P&& x); template <class P> iterator insert(const_iterator position, P&& x);1 Requires: P shall be convertible to value_type.
If P is instantiated as a reference type, then the argument x is copied from. Otherwise x is considered to be an rvalue as it is converted to value_type and inserted into the map. Specifically, in such cases CopyConstructible is not required of key_type or mapped_type unless the conversion from P specifically requires it (e.g., if P is a tuple<const key_type, mapped_type>, then key_type must be CopyConstructible). The signature taking InputIterator parameters does not require CopyConstructible of either key_type or mapped_type if the dereferenced InputIterator returns a non-const rvalue pair<key_type, mapped_type>. Otherwise CopyConstructible is required for both key_type and mapped_type. ? Remarks: These signatures shall not participate in overload resolution unless P is implicitly convertible to value_type.
Section: 23.2.5 [unord.req] Status: Tentatively NAD Submitter: Pablo Halpern Opened: 2010-10-18 Last modified: 2011-02-21
View other active issues in [unord.req].
View all other issues in [unord.req].
View all issues with Tentatively NAD status.
Discussion:
The current definition of emplace(args) for associative containers as described in Table 99 is:
Requires: T shall be constructible from args.
Effects: Inserts a T object t constructed with std::forward<Args>(args)... if and only if there is no element in the container with key equivalent to the key of t. The bool component of the returned pair is true if and only if the insertion takes place, and the iterator component of the pair points to the element with key equivalent to the key of t.
There is similar language in Table 100 for unordered associative containers.
The first issue is editorial: T should be value_type throughout both tables. The major issue is that, if the container is map, multimap, unordered_map, or unordered_multimap, then the only way to construct an object of value_type is to supply exactly two arguments for Key and Value, a pair<Key,Value>, or a piecewise_construct_t followed by two tuples. The original emplace() proposal would have allowed you to specify a Key value followed by any number of constructor arguments for Value. When we removed the variadic constructor to pair, this ability went away. I don't think that was deliberate. Fixing this is non-trivial, I think. I think that emplace() for map and multimap need several overloads: one for each overloaded constructor in pair<Key,Value>, and one for the emplace(Key, valueargs...) case. And it probably needs some SFINAE meta-programming to ensure that the last case doesn't override any of the other ones. Alternatively, one could say that there are exactly two cases: emplace(args) where pair<Key,Value> is constructible from args, and emplace(args) where Key is constructible form the first arg and Value is constructible from the rest. Alternatively, the status quo is to use piecewise_construct_t if you want to construct an object.[ 2010 Batavia: ]
N3178 was looked at in session and moved to NAD.
Proposed resolution:
Section: 23.4.4.3 [map.access] Status: Tentatively Ready Submitter: Matt Austern Opened: 2010-11-01 Last modified: 2011-02-21
View all other issues in [map.access].
View all issues with Tentatively Ready status.
Discussion:
In [map.access]/9, the Returns clause for map<Key, T>::at(x) says that it returns "a reference to the element whose key is equivalent to x." That can't be right. The signature for at() says that its return type is T, but the elements of map<Key, T> have type pair<const K, T>. (I checked [unord.map.elem] and found that its specification of at() is correct. This is a problem for map only.)
Proposed resolution:
Change the wording in [map.access]/9 so it's identical to what we already say for operator[], which is unambiguous and correct.
Returns: A reference to the
element whose key is equivalentmapped_type corresponding to x in *this.
Section: 30.6.9.1 [futures.task.members] Status: New Submitter: Pete Becker Opened: 2010-06-21 Last modified: 2011-02-21
View other active issues in [futures.task.members].
View all other issues in [futures.task.members].
View all issues with New status.
Discussion:
The Throws clause for packaged_task::operator() says that it throws "a future_error exception object if there is no associated asynchronous state or the stored task has already been invoked." However, the Error Conditions clause does not define an error condition when the stored task has already been invoked, only when the associated state is already ready (i.e. the invocation has completed).
[2011-02-17 Anthony provides an alternative resolution]
Previous proposed resolution:
Change the first bullet item in 30.6.9.1 [futures.task.members] /22:
void operator()(ArgTypes... args);20 ...
21 ...
22 Error conditions:
- promise_already_satisfied if
the associated asynchronous state is already readyoperator() has already been called.- no_state if *this has no associated asynchronous state.
Proposed resolution:
Change the first bullet item in 30.6.9.1 [futures.task.members] p. 17:
void operator()(ArgTypes... args);15 ...
16 ...
17 Error conditions:
- promise_already_satisfied if the
associated asynchronous state is already readystored task has already been invoked.- no_state if *this has no associated asynchronous state.
Change the first bullet item in 30.6.9.1 [futures.task.members] p. 21:
void make_ready_at_thread_exit(ArgTypes... args);19 ...
20 ...
21 Error conditions:
- promise_already_satisfied if the
associated asynchronous state already has a stored value or exceptionstored task has already been invoked.- no_state if *this has no associated asynchronous state.
Section: 21.5 [string.conversions] Status: Review Submitter: Alisdair Meredith Opened: 2010-07-19 Last modified: 2010-11-13
View all other issues in [string.conversions].
Discussion:
The functions (w)stoi and (w)stof are specified in terms of calling C library APIs for potentially wider types. The integer and floating-point versions have subtly different behaviour when reading values that are too large to convert. The floating point case will throw out_of_bound if the read value is too large to convert to the wider type used in the implementation, but behaviour is undefined if the converted value cannot narrow to a float. The integer case will throw out_of_bounds if the converted value cannot be represented in the narrower type, but throws invalid_argument, rather than out_of_bounds, if the conversion to the wider type fails due to overflow.
Suggest that the Throws clause for both specifications should be consistent, supporting the same set of fail-modes with the matching set of exceptions.
Proposed resolution:
21.5p3 [string.conversions]
int stoi(const string& str, size_t *idx = 0, int base = 10); long stol(const string& str, size_t *idx = 0, int base = 10); unsigned long stoul(const string& str, size_t *idx = 0, int base = 10); long long stoll(const string& str, size_t *idx = 0, int base = 10); unsigned long long stoull(const string& str, size_t *idx = 0, int base = 10);...
3 Throws: invalid_argument if strtol, strtoul, strtoll, or strtoull reports that no conversion could be performed. Throws out_of_range if strtol, strtoul, strtoll or strtoull sets errno to ERANGE, or if the converted value is outside the range of representable values for the return type.
21.5p6 [string.conversions]
float stof(const string& str, size_t *idx = 0); double stod(const string& str, size_t *idx = 0); long double stold(const string& str, size_t *idx = 0);...
6 Throws: invalid_argument if strtod or strtold reports that no conversion could be performed. Throws out_of_range if strtod or strtold sets errno to ERANGE or if the converted value is outside the range of representable values for the return type.
Section: 20.8.9.1.1 [func.bind.isbind] Status: Open Submitter: Sean Hunt Opened: 2010-07-19 Last modified: 2011-02-21
View all other issues in [func.bind.isbind].
View all issues with Open status.
Discussion:
20.8.9.1.1 [func.bind.isbind] says for is_bind_expression:
Users may specialize this template to indicate that a type should be treated as a subexpression in a bind call.
But it also says:
If T is a type returned from bind, is_bind_expression<T> shall be publicly derived from integral_constant<bool, true>, otherwise from integral_constant<bool, false>.
This means that while the user is free to specialize, any specialization would have to be false to avoid violating the second requirement. A similar problem exists for is_placeholder.
[ 2010 Batavia (post meeting session) ]
Alisdair recognises this is clearly a bug introduced by some wording he wrote, the sole purpose of this metafunction is as a customization point for users to write their own bind-expression types that participate in the standard library bind protocol. The consensus was that this should be fixed in Madrid, moved to Open.
Proposed resolution:
Section: 21.4.8.9 [string.io] Status: Open Submitter: James Kanze Opened: 2010-07-23 Last modified: 2011-02-21
View all other issues in [string.io].
View all issues with Open status.
Discussion:
What should the following code output?
#include <string> #include <iostream> #include <iomanip> int main() { std::string test("0X1Y2Z"); std::cout.fill('*'); std::cout.setf(std::ios::internal, std::ios::adjustfield); std::cout << std::setw(8) << test << std::endl; }
I would expect "**0X1Y2Z", and this is what the compilers I have access to (VC++, g++ and Sun CC) do. But according to the standard, it should be "0X**1Y2Z":
21.4.8.9 [string.io]/5:
template<class charT, class traits, class Allocator> basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>& os, const basic_string<charT,traits,Allocator>& str);Effects: Behaves as a formatted output function (27.7.3.6.1 [ostream.formatted.reqmts]). After constructing a sentry object, if this object returns true when converted to a value of type bool, determines padding as described in 22.4.2.2.2 [facet.num.put.virtuals], then inserts the resulting sequence of characters seq as if by calling os.rdbuf()->sputn(seq, n), where n is the larger of os.width() and str.size(); then calls os.width(0).
22.4.2.2.2 [facet.num.put.virtuals]/5:
[...]
Stage 3: A local variable is initialized as
fmtflags adjustfield= (flags & (ios_base::adjustfield));The location of any padding is determined according to Table 88.
If str.width() is nonzero and the number of charT's in the sequence after stage 2 is less than str.width(), then enough fill characters are added to the sequence at the position indicated for padding to bring the length of the sequence to str.width(). str.width(0) is called.
Table 88 — Fill padding State Location adjustfield == ios_base::left pad after adjustfield == ios_base::right pad before adjustfield == internal and a sign occurs in the representation pad after the sign adjustfield == internal and representation after stage 1 began with 0x or 0X pad after x or X otherwise pad before
Although it's not 100% clear what "the sequence after stage 2" should mean here, when there is no stage 2, the only reasonable assumption is that it is the contents of the string being output. In the above code, the string being output is "0X1Y2Z", which starts with "0X", so the padding should be inserted "after x or X", and not before the string. I believe that this is a defect in the standard, and not in the three compilers I tried.
[ 2010 Batavia (post meeting session) ]
Consensus that all known implementations are consistent, and disagree with the standard. Preference is to fix the standard before implementations start trying to conform to the current spec, as the current implementations have the preferred form. Howard volunteered to drught for Madrid, move to Open.
Proposed resolution:
Section: 23.4 [associative] Status: New Submitter: Paolo Carlini Opened: 2010-10-29 Last modified: 2011-02-21
View all other issues in [associative].
View all issues with New status.
Discussion:
I'm seeing something strange in the paragraphs 23.4.4.4 [map.modifiers] and 23.4.5.3 [multimap.modifiers]: they both talk about tuple<const key_type, mapped_type> but I think they should be talking about pair<const key_type, mapped_type> because, among other reasons, a tuple is not convertible to a pair. If I replace tuple with pair everything makes sense to me.
The proposed resolution is obvious.[ 2010-11-07 Daniel comments ]
This is by far not the only necessary fix within both sub-clauses. For details see the 2010-10-29 comment in 2005.
Proposed resolution:
Apply the resolution proposed by the 2010-10-29 comment in 2005.
Section: 17.6.5.6 [constexpr.functions] Status: New Submitter: Matt Austern Opened: 2010-11-12 Last modified: 2011-02-21
View all issues with New status.
Discussion:
Suppose that a particular function is not tagged as constexpr in the standard, but that, in some particular implementation, it is possible to write it within the constexpr constraints. If an implementer tags such a function as constexpr, is that a violation of the standard or is it a conforming extension?
There are two questions to consider. First, is this allowed under the as-if rule? Second, if it does not fall under as-if, is there (and should there be) any special license granted to implementers to do this anyway, sort of the way we allow elision of copy constructors even though it is detectable by users?
I believe that this does not fall under "as-if", so implementers probably don't have that freedom today. I suggest changing the WP to grant it. Even if we decide otherwise, however, I suggest that we make it explicit.
Proposed resolution:
In 17.6.4.6 [constexpr.functions], change paragraph 1 to:
This standard explicitly requires that certain standard library functions are constexpr [dcl.constexpr]. Additionally, an implementation may declare any function to be constexpr if that function's definition satisfies the necessary constraints. Within any header that provides any non-defining declarations of constexpr functions or constructors an implementation shall provide corresponding definitions.
Section: 17.6.4.3.1 [macro.names] Status: Tentatively Ready Submitter: Alberto Ganesh Barbati Opened: 2010-11-16 Last modified: 2011-02-21
View all other issues in [macro.names].
View all issues with Tentatively Ready status.
Discussion:
A program is currently forbidden to use keywords as macro names. This restriction should be strengthened to include all identifiers that could be used by the library as attribute-tokens (for example noreturn, which is used by header <cstdlib>) and the special identifiers introduced recently for override control (these are not currently used in the library public interface, but could potentially be used by the implementation or in future revisions of the library).
[2011-02-10 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
Modify 17.6.4.3.1 [macro.names] paragraph 2 as follows:
A translation unit shall not #define or #undef names lexically identical to keywords, to the identifiers listed in Table X [Identifiers with special meaning], or to the attribute-tokens described in clause 7.6 [dcl.attr].
Section: 20.9.4 [meta.unary] Status: New Submitter: Nikolay Ivchenkov Opened: 2010-11-08 Last modified: 2011-02-21
View all other issues in [meta.unary].
View all issues with New status.
Discussion:
According to N3126 ‑ 3.9/9,
"Scalar types, trivial class types (Clause 9), arrays of such types and cv‑qualified versions of these types (3.9.3) are collectively called trivial types."
Thus, an array (possibly of unknown bound) can be trivial type, non‑trivial type, or an array type whose triviality cannot be determined because its element type is incomplete.
According to N3126 ‑ Table 45, preconditions for std::is_trivial are defined as follows:
"T shall be a complete type, (possibly cv-qualified) void, or an array of unknown bound"
It seems that "an array of unknown bound" should be changed to "an array of unknown bound of a complete element type". Preconditions for some other templates (e.g., std::is_trivially_copyable, std::is_standard_layout, std::is_pod, and std::is_literal_type) should be changed similarly.
On the other hand, some preconditions look too restrictive. For example, std::is_empty and std::is_polymorphic might accept any incomplete non‑class type.
[2011-02-18: Daniel provides wording proposal]
While reviewing the individual preconditions I could find three different groups of either too weakening or too strengthening constraints:
is_empty/is_polymorphic/is_abstract/has_virtual_destructor:
These traits can only apply for non‑union class types, otherwise the result must always be false
is_base_of:
Similar to the previous bullet, but the current wording comes already near to that ideal, it only misses to add the non‑union aspect.
is_trivial/is_trivially_copyable/is_standard_layout/is_pod/is_literal_type:
These traits always require that std::remove_all_extents<T>::type to be cv void or a complete type.
Proposed resolution:
Modify the pre-conditions of the following type traits in 20.9.4.3 [meta.unary.prop], Table 48 — Type property predicates:
Table 48 — Type property predicates Template Condition Preconditions ... template <class T>
struct is_trivial;T is a trivial type (3.9) remove_all_extents<T>::type
shall be a complete type,or (possibly
cv-qualified) void, or an array of.
unknown boundtemplate <class T>
struct is_trivially_copyable;T is a trivially copyable
type (3.9)remove_all_extents<T>::type
shall be a complete type,or (possibly
cv-qualified) void, or an array of.
unknown boundtemplate <class T>
struct is_standard_layout;T is a standard-layout
type (3.9)remove_all_extents<T>::type
shall be a complete type,or (possibly
cv-qualified) void, or an array of.
unknown boundtemplate <class T>
struct is_pod;T is a POD type (3.9) remove_all_extents<T>::type
shall be a complete type,or (possibly
cv-qualified) void, or an array of.
unknown boundtemplate <class T>
struct is_literal_type;T is a literal type (3.9) remove_all_extents<T>::type
shall be a complete type,or (possibly
cv-qualified) void, or an array of.
unknown boundtemplate <class T>
struct is_empty;T is a class type, but not a
union type, with no
non-static data members
other than bit-fields of
length 0, no virtual
member functions, no
virtual base classes, and
no base class B for which
is_empty<B>::value is
false.T shall be a complete type,If T
(possibly cv-qualified) void, or
an array of unknown bound
is a non‑union class type, T
shall be a complete type.template <class T>
struct is_polymorphic;T is a polymorphic
class (10.3)T shall be a complete type,If T
type, (possibly cv-qualified) void, or
an array of unknown bound
is a non‑union class type, T
shall be a complete type.template <class T>
struct is_abstract;T is an abstract
class (10.4)T shall be a complete type,If T
type, (possibly cv-qualified) void, or
an array of unknown bound
is a non‑union class type, T
shall be a complete type.... template <class T>
struct has_virtual_destructor;T has a virtual
destructor (12.4)T shall be a complete type,If T
(possibly cv-qualified) void, or
an array of unknown bound
is a non‑union class type, T
shall be a complete type.
Modify the pre-conditions of the following type traits in 20.9.6 [meta.rel], Table 50 — Type relationship predicates:
Table 50 — Type relationship predicates Template Condition Comments ... template <class Base, class
Derived>
struct is_base_of;Base is a base class of
Derived (10) without
regard to cv-qualifiers
or Base and Derived
are not unions and
name the same class
type without regard to
cv-qualifiersIf Base and Derived are
non‑union class types
and are different types
(ignoring possible cv-qualifiers)
then Derived shall be a complete
type. [ Note: Base classes that
are private, protected, or
ambigious are, nonetheless, base
classes. — end note ]...
Section: 17.6.3.5 [allocator.requirements] Status: Open Submitter: Daniel Krügler Opened: 2010-11-17 Last modified: 2011-02-21
View all other issues in [allocator.requirements].
View all issues with Open status.
Discussion:
During the Batavia meeting it turned out that there is a definition hole for types satisfying the Allocators requirements: The problem became obvious when it was discussed whether all swap functions of Containers with internal data handles can be safely tagged with noexcept or not. While it is correct that the implicit swap function of an allocator is required to be a no-throw operation (because move/copy-constructors and assignment operators are required to be no-throw functions), there are no such requirements for specialized swap overloads for a particular allocator.
But this requirement is essential because the Containers are required to support swappable Allocators, when the value allocator_traits<>::propagate_on_container_swap evaluates to true.[2011-02-10 Alberto, Daniel, and Pablo collaborated on the proposed wording]
The proposed resolution (based on N3225) attempts to solve the following problems:
Proposed resolution:
Adapt the following three rows from Table 44 — Allocator requirements:
Table 44 — Allocator requirements Expression Return type Assertion/note
pre-/post-conditionDefault X::propagate_on_container_copy_assignment Identical to or derived from true_type
or false_typetrue_type only if an allocator of type X should be copied
when the client container is copy-assigned. See Note B, below.false_type X::propagate_on_container_move_assignment Identical to or derived from true_type
or false_typetrue_type only if an allocator of type X should be moved
when the client container is move-assigned. See Note B, below.false_type X::propagate_on_container_swap Identical to or derived from true_type
or false_typetrue_type only if an allocator of type X should be swapped
when the client container is swapped. See Note B, below.false_type
Following 17.6.3.5 [allocator.requirements] p. 3 insert a new normative paragraph:
Note B: If X::propagate_on_container_copy_assignment::value is true, X shall satisfy the CopyAssignable requirements (Table 39 [copyassignable]). If X::propagate_on_container_move_assignment::value is true, X shall satisfy the MoveAssignable requirements (Table 38 [moveassignable]) and the move operation shall not throw exceptions. If X::propagate_on_container_swap::value is true, lvalues of X shall be swappable (17.6.3.2 [swappable.requirements]) and the swap operation shall not throw exceptions.
Modify 23.2.1 [container.requirements.general] p. 8 and p. 9 as indicated:
8 - [..] The allocator may be replaced only via assignment or swap(). Allocator replacement is performed by copy assignment, move assignment, or swapping of the allocator only if allocator_traits<allocator_type>::propagate_on_container_copy_assignment::value, allocator_traits<allocator_type>::propagate_on_container_move_assignment::value, or allocator_traits<allocator_type>::propagate_on_container_swap::value is true within the implementation of the corresponding container operation.
9 - The expression a.swap(b), for containers a and b of a standard container type other than array, shall exchange the values of a and b without invoking any move, copy, or swap operations on the individual container elements. Lvalues of aThe behavior of a call to a container's swap function is undefined unless the objects being swapped have allocators that compare equal or allocator_traits<allocator_type>::propagate_on_container_swap::value is true. In all container types defined in this Clause, the member get_allocator() returns a copy of the allocator used to construct the container or, if that allocator has been replaced, a copy of the most recent replacement.Any Compare, Pred, or Hash objectsbelonging to a and b shall be swappable and shall be exchanged byunqualified calls to non-membercalling swap as described in 17.6.3.2 [swappable.requirements]. If allocator_traits<allocator_type>::propagate_on_container_swap::value is true, then lvalues of allocator_type shall be swappable and the allocators of a and b shall also be exchanged using aan unqualified call to non-memberswap call as described in 17.6.3.2 [swappable.requirements]. Otherwise,theythe allocators shall not be swapped, and the behavior is undefined unless a.get_allocator() == b.get_allocator(). Every iterator referring to an element in one container before the swap shall refer to the same element in the other container after the swap. It is unspecified whether an iterator with value a.end() before the swap will have value b.end() after the swap.
Section: 20.8.3 [refwrap] Status: Tentatively Ready Submitter: Nikolay Ivchenkov Opened: 2010-11-15 Last modified: 2011-02-25
View other active issues in [refwrap].
View all other issues in [refwrap].
View all issues with Tentatively Ready status.
Discussion:
std::reference_wrapper's function call operator uses wrong type encoding for rvalue-arguments. An rvalue-argument of type T must be encoded as T&&, not as just T.
#include <functional> #include <iostream> #include <string> #include <type_traits> #include <utility> template <class F, class... Types> typename std::result_of<F (Types...)>::type f1(F f, Types&&... params) { return f(std::forward<Types...>(params...)); } template <class F, class... Types> typename std::result_of<F (Types&&...)>::type f2(F f, Types&&... params) { return f(std::forward<Types...>(params...)); } struct Functor { template <class T> T&& operator()(T&& t) const { return static_cast<T&&>(t); } }; int main() { typedef std::string const Str; std::cout << f1(Functor(), Str("1")) << std::endl; // (1) std::cout << f2(Functor(), Str("2")) << std::endl; // (2) }
Lets consider the function template f1 (which is similar to std::reference_wrapper's function call operator). In the invocation (1) F is deduced as 'Functor' and Types is deduced as type sequence which consists of one type 'std::string const'. After the substitution we have the following equivalent:
template <> std::result_of<F (std::string const)>::type f1<Functor, std::string const>(Functor f, std::string const && params) { return f(std::forward<const std::string>(params)); }
The top-level cv-qualifier in the parameter type of 'F (std::string const)' is removed, so we have
template <> std::result_of<F (std::string)>::type f1<Functor, std::string const>(Functor f, std::string const && params) { return f(std::forward<const std::string>(params)); }
Let r be an rvalue of type 'std::string' and cr be an rvalue of type 'std::string const'. The expression Str("1") is cr. The corresponding return type for the invocation
Functor().operator()(r)
is 'std::string &&'. The corresponding return type for the invocation
Functor().operator()(cr)
is 'std::string const &&'.
std::result_of<Functor (std::string)>::type is the same type as the corresponding return type for the invocation Functor().operator()(r), i.e. it is 'std::string &&'. As a consequence, we have wrong reference binding in the return statement in f1. Now lets consider the invocation (2) of the function template f2. When the template arguments are substituted we have the following equivalent:template <> std::result_of<F (std::string const &&)>::type f2<Functor, std::string const>(Functor f, std::string const && params) { return f(std::forward<const std::string>(params)); }
std::result_of<F (std::string const &&)>::type is the same type as 'std::string const &&'. This is correct result.
[ 2010-12-07 Jonathan Wakely comments and suggests a proposed resolution ]
I agree with the analysis and I think this is a defect in the standard, it would be a shame if it can't be fixed.
In the following example one would expect f(Str("1")) and std::ref(f)(Str("2")) to be equivalent but the current wording makes the invocation through reference_wrapper ill-formed:#include <functional> #include <string> struct Functor { template <class T> T&& operator()(T&& t) const { return static_cast<T&&>(t); } }; int main() { typedef std::string const Str; Functor f; f( Str("1") ); std::ref(f)( Str("2") ); // error }
[ 2010-12-07 Daniel comments and refines the proposed resolution ]
There is one further defect in the usage of result_of within reference_wrapper's function call operator: According to 20.8.3.4 [refwrap.invoke] p. 1 the invokable entity of type T is provided as lvalue, but result_of is fed as if it were an rvalue. This does not only lead to potentially incorrect result types, but it will also have the effect that we could never use the function call operator with a function type, because the type encoding used in result_of would form an invalid function type return a function type. The following program demonstrates this problem:
#include <functional> void foo(int) {} int main() { std::ref(foo)(0); // error }
The correct solution is to ensure that T becomes T& within result_of, which solves both problems at once.
[2011-02-24 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
Change the synopsis in 20.8.3 [refwrap] paragraph 1:
namespace std { template <class T> class reference_wrapper { public : [...] // invocation template <class... ArgTypes> typename result_of<T&(ArgTypes&&...)>::type operator() (ArgTypes&&...) const; }; }
Change the signature in 20.8.3.4 [refwrap.invoke] before paragraph 1
template <class... ArgTypes> typename result_of<T&(ArgTypes&&... )>::type operator()(ArgTypes&&... args) const;1 Returns: INVOKE(get(), std::forward<ArgTypes>(args)...). (20.8.2)
Section: 28.7 [re.traits] Status: New Submitter: Jonathan Wakely Opened: 2010-11-16 Last modified: 2011-02-21
View all other issues in [re.traits].
View all issues with New status.
Discussion:
28.7 [re.traits] p. 12 says:
returns true if f bitwise or'ed with the result of calling lookup_classname with an iterator pair that designates the character sequence "w" is not equal to 0 and c == '_'
If the bitmask value corresponding to "w" has a non-zero value (which it must do) then the bitwise or with any value is also non-zero, and so isctype('_', f) returns true for any f. Obviously this is wrong, since '_' is not in every ctype category.
There's a similar problem with the following phrases discussing the "blank" char class.
Proposed resolution:
Replace the Returns clause with a description in terms of ctype categories, rather than pseudocode in terms of bitwise operations. (full replacement wording to follow)
Section: 22.3.3.1 [classification] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2010-11-16 Last modified: 2011-02-25
View all issues with Tentatively Ready status.
Discussion:
C99 added isblank and iswblank to <locale.h> but <locale> does not provide any equivalent.
[2011-02-24 Reflector discussion]
Moved to Tentatively Ready after 6 votes.
Proposed resolution:
Add to 22.3.3.1 [classification] synopsis:
template <class charT> bool isgraph (charT c, const locale& loc); template <class charT> bool isblank (charT c, const locale& loc);
Add to 22.4.1 [category.ctype] synopsis:
static const mask xdigit = 1 << 8; static const mask blank = 1 << 9; static const mask alnum = alpha | digit; static const mask graph = alnum | punct;
Section: 20.11.5.5 [time.duration.nonmember] Status: Tentatively Ready Submitter: Daniel Krügler Opened: 2010-12-06 Last modified: 2011-02-21
View other active issues in [time.duration.nonmember].
View all other issues in [time.duration.nonmember].
View all issues with Tentatively Ready status.
Discussion:
As of issue 1171 several time-utility functions have been marked constexpr. Alas this was done without adapting the corresponding return elements, which has the effect that none of current arithmetic functions of class template duration marked as constexpr can ever be constexpr functions (which makes them ill-formed, no diagnostics required as of recent core rules), because they invoke a non-constant expression, e.g. 20.11.5.5 [time.duration.nonmember]/2:
template <class Rep1, class Period1, class Rep2, class Period2> constexpr typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>{>}::type operator+(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs); 2 Returns: CD(lhs) += rhs.
The real problem is, that we cannot defer to as-if rules here: The returns element specifies an indirect calling contract of a potentially user-defined function. This cannot be the += assignment operator of such a user-defined type, but must be the corresponding immutable binary operator+ (unless we require that += shall be an immutable function which does not really makes sense).
[2011-02-17 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
The suggested wording changes are against the working draft N3225. Additional to the normative wording changes some editorial fixes are suggested.
Change the following arithmetic function specifications as follows:
template <class Rep1, class Period1, class Rep2, class Period2> constexpr typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>{>}::type operator+(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);2 Returns:
CD(lhs) += rhsCD(CD(lhs).count() + CD(rhs).count()).
template <class Rep1, class Period1, class Rep2, class Period2> constexpr typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>{>}::type operator-(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);3 Returns:
CD(lhs) -= rhsCD(CD(lhs).count() - CD(rhs).count()).
template <class Rep1, class Period, class Rep2> constexpr duration<typename common_type<Rep1, Rep2>::type, Period> operator*(const duration<Rep1, Period>& d, const Rep2& s);4 Remarks: This operator shall not participate in overload resolution unless Rep2 is implicitly convertible to CR(Rep1, Rep2).
5 Returns:duration<CR(Rep1, Rep2), Period>(d) *= sCD(CD(d).count() * s).
[...]
template <class Rep1, class Period, class Rep2> constexpr duration<typename common_type<Rep1, Rep2>::type, Period> operator/(const duration<Rep1, Period>& d, const Rep2& s);8 Remarks: This operator shall not participate in overload resolution unless Rep2 is implicitly convertible to CR(Rep1, Rep2) and Rep2 is not an instantiation of duration.
9 Returns:duration<CR(Rep1, Rep2), Period>(d) /= sCD(CD(d).count() / s).
[...]
template <class Rep1, class Period, class Rep2> constexpr duration<typename common_type<Rep1, Rep2>::type, Period> operator%(const duration<Rep1, Period>& d, const Rep2& s);11 Remarks: This operator shall not participate in overload resolution unless Rep2 is implicitly convertible to CR(Rep1, Rep2) and Rep2 is not an instantiation of duration.
12 Returns:duration<CR(Rep1, Rep2), Period>(d) %= sCD(CD(d).count() % s)
template <class Rep1, class Period1, class Rep2, class Period2> constexpr typename common_type<duration<Rep1, Period1>, duration<Rep2, Period2>>::type operator%(const duration<Rep1, Period1>& lhs, const duration<Rep2, Period2>& rhs);13 Returns:
common_type<duration<Rep1, Period1>, duration<Rep2, Period2> >::type(lhs) %= rhsCD(CD(lhs).count() % CD(rhs).count()).
Section: 20.8.9.1.2 [func.bind.bind], 30.6.1 [futures.overview], 30.6.8 [futures.async] Status: New Submitter: Daniel Krügler Opened: 2010-12-07 Last modified: 2011-02-21
View all other issues in [func.bind.bind].
View all issues with New status.
Discussion:
Issue 2017 points out some incorrect usages of result_of in the declaration of the function call operator overload of reference_wrapper, but there are more such specification defects:
[..] The effect of g(u1, u2, ..., uM) shall be INVOKE(fd, v1, v2, ..., vN, result_of<FD cv (V1, V2, ..., VN)>::type) [..]
but fd is defined as "an lvalue of type FD constructed from std::forward<F>(f)". This means that the above usage must refer to result_of<FD cv & (V1, V2, ..., VN)> instead.
Similar in 20.8.9.1.2 [func.bind.bind] p. 10 bullet 2 we have:
if the value of is_bind_expression<TiD>::value is true, the argument is tid(std::forward<Uj>(uj)...) and its type Vi is result_of<TiD cv (Uj...)>::type
Again, tid is defined as "lvalue of type TiD constructed from std::forward<Ti>(ti)". This means that the above usage must refer to result_of<TiD cv & (Uj...)> instead. We also have similar defect as in 2017 in regard to the argument types, this leads us to the further corrected form result_of<TiD cv & (Uj&&...)>. This is not the end: Since the Vi are similar sensitive to the argument problem, the last part must say:
"[..] its type Vi is result_of<TiD cv & (Uj&&...)>::type &&" (The bound arguments Vi can never be void types, therefore we don't need to use the more defensive std::add_rvalue_reference type trait)The function template async is declared as follows (the other overload has the same problem):
template <class F, class... Args> future<typename result_of<F(Args...)>::type> async(F&& f, Args&&... args);
This usage has the some same problems as we have found in reference_wrapper (2017) and more: According to the specification in 30.6.8 [futures.async] the effective result type is that of the call of
INVOKE(decay_copy(std::forward<F>(f)), decay_copy(std::forward<Args>(args))...)
First, decay_copy potentially modifies the effective types to decay<F>::type and decay<Args>::type.... Second, the current specification is not really clear, what the value category of callable type or the arguments shall be: According to the second bullet of 30.6.8 [futures.async] p. 3:
Invocation of the deferred function evaluates INVOKE(g, xyz) where g is the stored value of decay_copy(std::forward<F>(f)) and xyz is the stored copy of decay_copy(std::forward<Args>(args))....
This seems to imply that lvalues are provided in contrast to the direct call expression of 30.6.8 [futures.async] p. 2 which implies rvalues instead. The specification needs to be clarified.
Proposed resolution:
The suggested wording changes are against the working draft N3225.
Change 20.8.9.1.2 [func.bind.bind] p. 3 as indicated:
Returns: A forwarding call wrapper g with a weak result type (20.8.2). The effect of g(u1, u2, ..., uM) shall be INVOKE(fd, v1, v2, ..., vN, result_of<FD cv & (V1, V2, ..., VN)>::type), where cv represents the cv-qualifiers of g and the values and types of the bound arguments v1, v2, ..., vN are determined as specified below. [..]
Change 20.8.9.1.2 [func.bind.bind] p. 10 bullet 2 as indicated:
if the value of is_bind_expression<TiD>::value is true, the argument is tid(std::forward<Uj>(uj)...) and its type Vi is result_of<TiD cv & (Uj&&...)>::type&&;
This resolution assumes that the wording of 30.6.8 [futures.async] is incorrectly implying rvalues as arguments of INVOKE, those should be lvalues instead.
Change the function signatures in header <future> synopsis 30.6.1 [futures.overview] p. 1 and in 30.6.8 [futures.async] p. 1 as indicated:
template <class F, class... Args> future<typename result_of<typename decay<F>::type&(typename decay<Args>::type&...)>::type> async(F&& f, Args&&... args); template <class F, class... Args> future<typename result_of<typename decay<F>::type&(typename decay<Args>::type&...)>::type> async(launch policy, F&& f, Args&&... args);
Change 30.6.8 [futures.async] p. 4 as indicated: [Note: There is one tiny editorial correction that completes one :: scope specifier] [Note: This sub-section need more wording: The call expressions used imply a different value category]
Returns: an object of type future<typename result_of<typename decay<F>::type&(typename decay<Args>::type&...)>::type> that refers to the associated asynchronous state created by this call to async.
Section: 20.8.3 [refwrap] Status: Tentatively Ready Submitter: Daniel Krügler Opened: 2010-12-08 Last modified: 2011-02-24
View other active issues in [refwrap].
View all other issues in [refwrap].
View all issues with Tentatively Ready status.
Discussion:
Issue 1295 correctly removed function types and references to function types from the bullet 1 of 20.8.2 [func.require] p. 3 because neither function types nor function references satisfy the requirements for a target object which is defined to be an object of a callable type. This has the effect that the reference in 20.8.3 [refwrap] p. 2
reference_wrapper has a weak result type (20.8.2).
is insufficient as a reference to define the member type result_type when the template argument T is a function type.
There are basically two approaches to solve the problem:Extend the definition of a weak result type in 20.8.2 [func.require] p. 3 to both function types and references thereof. This extension must be specified independend from the concept of a call wrapper, though.
Add one extra sentence to 20.8.3 [refwrap] p. 2 that simply defines the member type result_type for reference_wrapper<T>, when T is a function type.
I checked the current usages of weak result type to have a base to argue for one or the other approach. It turns out, that there is no further reference to this definition in regard to function types or references thereof. The only other reference can be found in 20.8.9.1.2 [func.bind.bind] p. 3, where g is required to be a class type.
[2011-02-23 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
The suggested wording changes are against the working draft N3225.
Change 20.8.3 [refwrap] p. 2 as indicated:
2 reference_wrapper<T> has a weak result type (20.8.2). If T is a function type, result_type shall be a synonym for the return type of T.
Section: 30.4.2.1 [thread.lock.guard], 30.4.2.2 [thread.lock.unique] Status: Tentatively Ready Submitter: Daniel Krügler Opened: 2010-12-08 Last modified: 2011-02-25
View all issues with Tentatively Ready status.
Discussion:
There are two different *Lockable requirements imposed on template arguments of the class template lock_guard as of 30.4.2.1 [thread.lock.guard] p. 1+2:
1 [..] The supplied Mutex type shall meet the BasicLockable requirements (30.2.5.2).
2 The supplied Mutex type shall meet the Lockable requirements (30.2.5.3).
The Lockable requirements include the availability of a member function try_lock(), but there is no operational semantics in the specification of lock_guard that would rely on such a function. It seems to me that paragraph 2 should be removed.
Similarly, 30.4.2.2 [thread.lock.unique] p. 1+2 refer to exactly the same two requirements. In this case it seems as if the intention was that the template arguement Mutex should always provide the try_lock() member function, because several member functions of unique_lock (unique_lock(mutex_type& m, try_to_lock_t) or bool try_lock()) take advantage of such a function without adding extra requirements for this. It seems that the requirement subset BasicLockable should be removed. I searched for further possible misusages of the *Lockable requirements, but could not find any more.[2011-02-23]
Howard suggests an alternative approach in regard to unique_lock: The current minimum requirements on its template argument should better be reduced to BasicLockable instead of the current Lockable, including ammending member-wise constraints where required. This suggestions was supported by Anthony, Daniel, and Pablo.
Daniel drafts wording that follows this separation strategy.[2011-02-24 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
The suggested wording changes are against the working draft N3225.
Remove 30.4.2.1 [thread.lock.guard] p. 2 completely:
2 The supplied Mutex type shall meet the Lockable requirements (30.2.5.3).
Change 30.4.2.2 [thread.lock.unique] p. 1-3 as indicated. The intend is to make BasicLockable the fundamental requirement for unique_lock. We also update the note to reflect these changes and synchronize one remaining reference of 'mutex' by the proper term 'lockable object' in sync to the wording changes of lock_guard:
1 [..] The behavior of a program is undefined if the contained pointer pm is not null and the
mutexlockable object pointed to by pm does not exist for the entire remaining lifetime (3.8) of the unique_lock object. The supplied Mutex type shall meet the BasicLockable requirements (30.2.5.2).[Editor's note: BasicLockable is redundant, since the following additional paragraph requires Lockable.]
2 The supplied Mutex type shall meet the Lockable requirements (30.2.5.3).
3 [ Note: unique_lock<Mutex> meets the BasicLockable requirements. If Mutex meets the Lockable requirements ([thread.req.lockable.req]), unique_lock<Mutex> also meets the Lockable requirements and if Mutex meets the TimedLockable requirements (30.2.5.4), unique_lock<Mutex> also meets the TimedLockable requirements. — end note ]
Modify 30.4.2.2.1 [thread.lock.unique.cons] to add the now necessary member-wise additional constraints for Lockable:
unique_lock(mutex_type& m, try_to_lock_t) noexcept;8 Requires: The supplied Mutex type shall meet the Lockable requirements ([thread.req.lockable.req]). If mutex_type is not a recursive mutex the calling thread does not own the mutex.
9 Effects: Constructs an object of type unique_lock and calls m.try_lock().
Modify 30.4.2.2.2 [thread.lock.unique.locking] to add the now necessary member-wise additional constraints for Lockable:
bool try_lock();? Requires: The supplied Mutex type shall meet the Lockable requirements ([thread.req.lockable.req]).
4 Effects: pm->try_lock()
Section: 29.5 [atomics.types.generic] Status: Tentatively Ready Submitter: Daniel Krügler Opened: 2010-12-08 Last modified: 2011-02-21
View all other issues in [atomics.types.generic].
View all issues with Tentatively Ready status.
Discussion:
Paragraph 5 and 6 of 29.5 [atomics.types.generic] impose different requirements on implementations for specializations of the atomic class template for integral types and for pointer types:
5 The atomic integral specializations and the specialization atomic<bool> shall have standard layout. They shall each have a trivial default constructor and a trivial destructor. They shall each support aggregate initialization syntax.
6 There are pointer partial specializations on the atomic class template. These specializations shall have trivial default constructors and trivial destructors.
It looks like an oversight to me, that for pointer specializations the requirements for standard layout and support for aggregate initialization syntax are omitted. In fact, this been confirmed by the N3193 proposal author. I suggest to impose the same implementation requirements for pointer types as for integral types, this should not impose unrealistic requirements on implementations.
[2011-02-10 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
The suggested wording changes are against the working draft N3225.
Change 29.5 [atomics.types.generic] p. 6 as indicated:
6 There are pointer partial specializations on the atomic class template. These specializations shall have standard layout, trivial default constructors, and trivial destructors. They shall each support aggregate initialization syntax.
Section: 30.6.9.1 [futures.task.members] Status: New Submitter: Daniel Krügler Opened: 2010-12-08 Last modified: 2011-02-21
View other active issues in [futures.task.members].
View all other issues in [futures.task.members].
View all issues with New status.
Discussion:
According to 30.6.9.1 [futures.task.members] p. 7 bullet 2:
packaged_task& operator=(packaged_task&& other);7 Effects:
[...]
packaged_task<R, ArgTypes...>(other).swap(*this).
The argument other given to the move constructor is an lvalue and must be converted into an rvalue via appropriate usage of std::move.
Proposed resolution:
The suggested wording changes are against the working draft N3225.
Change 30.6.9.1 [futures.task.members] p. 7 bullet 2 as indicated:
packaged_task& operator=(packaged_task&& other);7 Effects:
[...]
packaged_task<R, ArgTypes...>(std::move(other)).swap(*this).
Section: 23.5 [unord] Status: Tentatively NAD Submitter: Pete Becker Opened: 2011-02-07 Last modified: 2011-02-28
View all other issues in [unord].
View all issues with Tentatively NAD status.
Discussion:
Tom Plum pointed out to me that there's an apparent inconsistency in the std:: qualification of template names in the unordered containers:
template <class Key, class T, class Hash = hash<Key>, class Pred = std::equal_to<Key>, class Alloc = std::allocator<std::pair<const Key, T> > > class unordered_map;
Is there a reason that hash is not qualified with std::? TR1 also does not use std:: here.
[ 2011-02-07 Chris Jefferson adds: ]
I assumed (I might be wrong) it is because hash is designed to be a customisation point, like swap.
[ 2011-02-07 Howard Hinnant adds: ]
I think this is incorrect. We mean std::hash, though clients are free to specialize std::hash on user-defined types. With the possible exception of begin/end (which I'm not sure if we've settled that), swap is the only intended customization point (look up a function by ADL) in the std:: lib.
[ 2011-02-24 Chris Jefferson adds: ]
I recommend NAD, due to 17.6.1.1 [contents] p3:
Whenever a name x defined in the standard library is mentioned, the name x is assumed to be fully qualified as ::std::x, unless explicitly described otherwise. For example, if the Effects section for library function F is described as calling library function G, the function ::std::G is meant.
[2011-02-25 Reflector discussion]
Moved to Tentatively NAD after 5 votes.
Proposed resolution:
Section: 30.6.9.1 [futures.task.members] Status: Tentatively Ready Submitter: Alberto Ganesh Barbati Opened: 2011-02-09 Last modified: 2011-02-28
View other active issues in [futures.task.members].
View all other issues in [futures.task.members].
View all issues with Tentatively Ready status.
Discussion:
Related with LWG issue 1514.
The move constructor of packaged_task does not specify how the stored task is constructed. The obvious way is to move-construct it using the task stored in the argument. Moreover, the constructor should be provided with a throws clause similar to one used for the other constructors, as the move constructor of the stored task is not required to be nothrow.
As for the other constructors, the terms "stores a copy of f" do not reflect the intent, which is to allow f to be moved when possible.
[2011-02-25: Alberto updates wording]
[2011-02-26 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
(wording written assuming LWG 1514 is also accepted)
Change 30.6.9.1 [futures.task.members] paragraph 3:
3 Effects: constructs a new packaged_task object with an associated asynchronous state and
stores a copy of f as the object's stored taskinitializes the object's stored task with std::forward<F>(f). The constructors that take an Allocator argument use it to allocate memory needed to store the internal data structures.
Change 30.6.9.1 [futures.task.members] paragraph 5:
5 Effects: constructs a new packaged_task object and transfers ownership of other's associated asynchronous state to *this, leaving other with no associated asynchronous state. Moves the stored task from other to *this.
Section: 22.4.7.1 [locale.messages] Status: New Submitter: Howard Hinnant Opened: 2011-02-14 Last modified: 2011-02-25
View all issues with New status.
Discussion:
In 22.4.7.1 [locale.messages], messages_base::catalog is specified to be a typedef to int. This type is subsequently used to open, access and close catalogs.
However, an OS may have catalog/messaging services that are indexed and managed by types other than int. For example POSIX, publishes the following messaging API:
typedef unspecified nl_catd; nl_catd catopen(const char* name , int oflag); char* catgets(nl_catd catd, int set_id, int msg_id, const char* s); int catclose(nl_catd catd);
I.e., the catalog is managed with an unspecified type, not necessarily an int. Mac OS uses a void* for nl_catd (which is conforming to the POSIX standard). The current messages_base spec effectively outlaws using the built-in OS messaging service supplied for this very purpose!
[2011-02-24: Chris Jefferson updates the proposed wording, changing unspecified to unspecified signed integral type]
Proposed resolution:
Modify 22.4.7.1 [locale.messages]:
namespace std { class messages_base { public: typedefintunspecified signed integral type catalog; }; ... }
Section: 28.8 [re.regex] Status: Tentatively Ready Submitter: Jonathan Wakely Opened: 2011-02-16 Last modified: 2011-02-25
View other active issues in [re.regex].
View all other issues in [re.regex].
View all issues with Tentatively Ready status.
Discussion:
N3149 replaced the "Throws: nothing" clause on basic_regex::assign(basic_regex&&) with the noexcept keyword. The effects of the move-assignment operator are defined in terms of the assign() function, so the "Throws: nothing" applied there too, and a noexcept-specification should be added there too.
[2011-02-24 Reflector discussion]
Moved to Tentatively Ready after 7 votes.
Proposed resolution:
Modify the basic_regex synopsis in 28.8 [re.regex] p. 3:
namespace std { template <class charT, class traits = regex_traits<charT> > class basic_regex { public: ... basic_regex& operator=(const basic_regex&); basic_regex& operator=(basic_regex&&) noexcept; basic_regex& operator=(const charT* ptr); ... }; }
Modify 28.8.3 [re.regex.assign] p. 2:
basic_regex& operator=(basic_regex&& e) noexcept;2 Effects: returns assign(std::move(e)).
Section: 30.6.9 [futures.task] Status: Tentatively Ready Submitter: Anthony Williams Opened: 2010-11-12 Last modified: 2011-02-25
View all other issues in [futures.task].
View all issues with Tentatively Ready status.
Discussion:
packaged_task::operator() always returns void, regardless of the return type of the wrapped task. However, packaged_task::result_type is a typedef to the return type of the wrapped task. This is inconsistent with other uses of result_type in the standard, where it matches the return type of operator() (e.g. function, owner_less). This is confusing.
It also violates the TR1 result_of protocol, and thus makes packaged_task harder to use with anything that respects that protocol.
Finally, it is of little use anyway.
packaged_task::result_type should therefore be removed.
[2011-02-24 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
Alter the class definition of packaged_task in 30.6.9 [futures.task] p. 2 as follows:
template<class R, class... ArgTypes> class packaged_task<R(ArgTypes...)> { public:typedef R result_type;[...] };
Section: 30.6.6 [futures.unique_future] Status: Tentatively Ready Submitter: Anthony Williams Opened: 2011-02-17 Last modified: 2011-02-22
View all other issues in [futures.unique_future].
View all issues with Tentatively Ready status.
Discussion:
As specified, future<>::share() has the signature
shared_future<R> share() &&;
This means that it can only be applied to rvalues. One of the key benefits of share() is that it can be used with the new auto facility:
std::promise<some_long_winded_type_name> some_promise; auto f = some_promise.get_future(); // std::future auto sf = std::move(f).share();
share() is sufficiently explicit that the move should not be required. We should be able to write:
auto sf = f.share();
[2011-02-22 Reflector discussion]
Moved to Tentatively Ready after 5 votes.
Proposed resolution:
Alter the declaration of share() to remove the "&&" rvalue qualifier in 30.6.6 [futures.unique_future] p. 3, and 30.6.6 [futures.unique_future] p. 11:
shared_future<R> share()&&;
Section: 30.6.8 [futures.async] Status: New Submitter: Alberto Ganesh Barbati Opened: 2011-02-17 Last modified: 2011-02-21
View all other issues in [futures.async].
View all issues with New status.
Discussion:
Clause 30.6.8 [futures.async] has undergone significant rewording in Batavia. Due to co-presence of at least three different sources of modification there is a part where changes have overlapped (marked by an Editor's note), which should be reconciled. Moreover, I believe that a few non-overlapping sentences are now incorrect and should be fixed, so the problem cannot be handled editorially. (See c++std-lib-29667.)
Proposed resolution:
Edit 30.6.4 [futures.state], paragraph 3 as follows.
An asynchronous return object is an object that reads results from an associated asynchronous state. A waiting function of an asynchronous return object is one that potentially blocks to wait for the associated asynchronous state to be made ready. If a waiting function can return before the state is made ready because of a timeout (30.2.5), then it is a timed waiting function, otherwise it is a non-timed waiting function.
Edit within 30.6.8 [futures.async] paragraph 3 bullet 2 as follows.
Effects: [...]
- if
policy & launch::deferred
is non-zero — [...] The associated asynchronous state is not made ready until the function has completed. The first call to a non-timed waiting function (30.6.4 [futures.state])requiring a non-timed waiton an asynchronous return object referring tothethis associated asynchronous statecreated by thisshall invoke the deferred function in the thread that called the waiting functionasync
call to become ready;.onceOnce evaluation ofINVOKE(g, xyz)
begins, the function is no longer considered deferred. [...]
Edit 30.6.8 [futures.async] paragraph 5 as follows.
Synchronization: Regardless of the provided
policy
argument,
- the invocation of
async
synchronizes with (1.10) the invocation off
. [Note: this statement applies even when the corresponding future object is moved to another thread. —end note]; and- the completion of the function
f
is sequenced before (1.10) the associated asynchronous state is made ready. [Note:f
might not be called at all, so its completion might never happen. —end note]
IfIf the implementation chooses thepolicy & launch::async
is non-zero,launch::async
policy,
- a call to a waiting function on an asynchronous return object that shares the associated asynchronous state created by this
async
call shall block until the associated thread has completed, as if joined (30.3.1.5);thethe associated thread completion synchronizes with (1.10) the return from the first function that successfully detects the ready status of the associated asynchronous state or with the return from the last function that releases the associated asynchronous statejoin()
on the created thread objectreturns, whichever happens first.[Editor's note: N3196 changes the following sentence as indicated. N3188 removes the sentence. Please pick one.] If the invocation is deferred, the completion of the invocation of the deferred function synchronizes with the successful return from a call to a waiting function on the associated asynchronous state.
Section: 23.3.6.3 [vector.capacity], 23.3.3.3 [deque.capacity] Status: New Submitter: Nikolay Ivchenkov Opened: 2011-02-20 Last modified: 2011-02-22
View all other issues in [vector.capacity].
View all issues with New status.
Discussion:
I have several questions with regard to the working paper N3225 (C++0x working draft):
Where the working draft specifies preconditions for shrink_to_fit member function of std::vector and std::deque?
Where the working draft specifies preconditions for 'void reserve(size_type n)' member function of std::vector?
Does a call to 'void resize(size_type sz)' of std::vector require the element type to be DefaultConstructible? If yes, why such requirement is not listed in the Requires paragraph?
Does a call to 'void resize(size_type sz)' of std::vector require the element type to be MoveAssignable because the call erase(begin() + sz, end()) mentioned in the Effects paragraph would require the element type to be MoveAssignable?
Why CopyInsertable requirement is used for 'void resize(size_type sz)' of std::vector instead of MoveInsertable requirement?
Proposed resolution:
Section: 29.3 [atomics.order] Status: New Submitter: Hans Boehm Opened: 2011-02-26 Last modified: 2011-02-28
View other active issues in [atomics.order].
View all other issues in [atomics.order].
View all issues with New status.
Discussion:
This violates the core intent of the memory model, as stated in the note in 1.10 [intro.multithread] p. 21.
This was discovered by Mark Batty, and pointed out in their POPL 2011 paper, "Mathematizing C++ Concurrency", section 4, "Sequential consistency of SC atomics". The problem is quite technical, but well-explained in that paper.
This particular issue was not understood at the time the FCD comments were generated. But it is closely related to a number of FCD comments. It should have arisen from US-171, though that's not the actual history.
This issue has been under discussion for several months in a group that included a half dozen or so of the most interested committee members. The P/R represents a well-considered consensus among us:
Proposed resolution:
Modify 29.3 [atomics.order] p.3, so that the normative part reads:
3 There shall be a single total order S on all memory_order_seq_cst operations, consistent with the "happens before" order and modification orders for all affected locations, such that each memory_order_seq_cst operation that loads a value observes either the last preceding modification according to this order S, A, or the result of an operation X that is not memory_order_seq_cst. Furthermore, if there is a last preceding memory_order_seq_cst modification A, then X must not happen before A. [ Note: Although it is not explicitly required that S include locks, it can always be extended to an order that does include lock and unlock operations, since the ordering between those is already included in the "happens before" ordering. — end note ]
Section: 24.2.4 [output.iterators] Status: New Submitter: Daniel Krügler Opened: 2011-02-27 Last modified: 2011-02-28
View all other issues in [output.iterators].
View all issues with New status.
Discussion:
During the Pittsburgh meeting the proposal N3066 became accepted because it fixed several severe issues related to the iterator specification. But the current working draft (N3225) does not reflect all these changes. Since I'm unaware whether every correction can be done editorial, this issue is submitted to take care of that. To give one example: All expressions of Table 108 — "Output iterator requirements" have a post-condition that the iterator is incrementable. This is impossible, because it would exclude any finite sequence that is accessed by an output iterator, such as a pointer to a C array. The N3066 wording changes did not have these effects.
Proposed resolution:
Modify the column contents of Table 108 — "Output iterator requirements", 24.2.4 [output.iterators], as indicated:
Table 108 — Output iterator requirements (in addition to Iterator) Expression Return type Operational semantics Assertion⁄note
pre-⁄post-condition*r = o result is not used Remark: After this operation
r is not required to be
dereferenceable.
post: r is incrementable.++r X& &r == &++r.
Remark: After this operation
r is not required to be
dereferenceable or incrementable.
post: r is incrementable.r++ convertible to const X& { X tmp = r;
++r;
return tmp; }Remark: After this operation
r is not required to be
dereferenceable or incrementable.
post: r is incrementable.*r++ = o result is not used Remark: After this operation
r is not required to be
dereferenceable or incrementable.
post: r is incrementable.