Revised 2015-05-23 at 15:05:40 UTC
Section: 23.2 [container.requirements] Status: Tentatively NAD Submitter: Paolo Carlini Opened: 2007-11-11 Last modified: 2015-04-08
View other active issues in [container.requirements].
View all other issues in [container.requirements].
View all issues with Tentatively NAD status.
Discussion:
In an emplace member function the function parameter pack may be bound to a priori unlimited number of objects: some or all of them can be elements of the container itself. Apparently, in order to conform to the blanket statement 23.2 [container.requirements]/11, the implementation must check all of them for that possibility. A possible solution can involve extending the exception in 23.2 [container.requirements]/12 also to the emplace member. As a side note, the push_back and push_front member functions are luckily not affected by this problem, can be efficiently implemented anyway.
[ Related to 767 and to 2164 ]
[ Bellevue: ]
The proposed addition (13) is partially redundant with the existing paragraph 12. Why was the qualifier "rvalues" added to paragraph 12? Why does it not cover subelements and pointers?
Resolution: Alan Talbot to rework language, then set state to Review.
[ 2009-07 Frankfurt ]
The problem is broader than emplace. The LWG doesn't feel that it knows how to write wording that prohibits all of the problematic use cases at this time.
NAD Future.
[2015-02 Cologne]
LWG believes that 2164 addresses this issue and therefore considers 760 as NAD.
Proposed resolution:
Add after 23.2 [container.requirements]/12:
-12- Objects passed to member functions of a container as rvalue references shall not be elements of that container. No diagnostic required.
-13- Objects bound to the function parameter pack of the emplace member function shall not be elements or sub-objects of elements of the container. No diagnostic required.
Section: 17.6.4.10 [res.on.objects] Status: Tentatively Ready Submitter: Geoffrey Romer Opened: 2012-12-17 Last modified: 2015-05-05
View all other issues in [res.on.objects].
Discussion:
The standard currently does not discuss when library objects may be accessed, except in a non-normative note pertaining to synchronization in [res.on.objects], leaving it ambiguous whether single-threaded code can access a library object during its construction or destruction. For example, there is a reasonable question as to what happens if the deleter supplied to a unique_ptr transitively accesses the unique_ptr itself during unique_ptr's destruction; a straightforward reading suggests that this is permitted, and that the deleter will see the unique_ptr still holding the originally stored pointer, but consensus on the LWG reflector indicates this was not the intent (see discussion beginning with c++std-lib-33362).
[2013-03-15 Issues Teleconference]
Moved to Open.
Geoffrey will provide an example that clearly highlights the issue.
[2013-03-19 Geoffrey provides revised resolution and an example]
I contend that the most straightforward reading of the current standard requires the following example code to print "good" (because ~unique_ptr is not specified to modify the state of the internal pointer), but the consensus on the reflector was that its behavior should be undefined.
This example also shows that, contrary to a comment in the telecon, the PR is not tautological. 12.7 [class.cdtor]/p4 explicitly permits member function calls during destruction, so the behavior of this code is well-defined as far as the core language is concerned, despite the fact that it accesses a library object after the end of the object's lifetime. If we want this code to have undefined behavior, we need to specify that at the library level.#include <memory> #include <iostream> class A; struct B { std::unique_ptr<A> a; }; struct A { B* b; ~A() { if (b->a.get() == this) { std::cout << "good" << std::endl; } } }; int main() { B b; b.a.reset(new A); b.a->b = &b; }
Previous resolution:
Change the title of sub-clause 17.6.4.10 [res.on.objects] as indicated:
Shared objects and the libraryLibrary object access [res.on.objects]Edit 17.6.4.10 [res.on.objects] p2 as indicated:
-2-
[Note: In particular, the program is required to ensure that completion of the constructor of any object of a class type defined in the standard library happens before any other member function invocation on that object and, unless otherwise specified, to ensure that completion of any member function invocation other than destruction on such an object happens before destruction of that object. This applies even to objects such as mutexes intended for thread synchronization. — end note]If an object of a standard library type is accessed outside of the object's lifetime (3.8 [basic.life]), the behavior is undefined unless otherwise specified.
[2014 Urbana]
STL: is this resolved by our change to the reeentrancy rules? [LWG 2414]
GR: don't think that solves the multi-threaded case
MC: I like changing the note to normative text
GR: uses the magic "happens before" words, and "access" is magic too
JW: I like this. strict improvement, uses the right wording we have to say this properly
STL: I like the last sentence of the note, could we add that as a new note at the end?
So add "[Note: This applies even to objects such as mutexes intended for thread synchronization.]" to the end and move to Ready
Proposed resolution:
This wording is relative to N3485.
Change the title of sub-clause 17.6.4.10 [res.on.objects] as indicated:
Shared objects and the libraryLibrary object access [res.on.objects]
Edit 17.6.4.10 [res.on.objects] p2 as indicated: [Editorial remark: The motivation, is to be more precise about the meaning of "outside the object's lifetime" in the presence of threads — end editorial remark]
-2- [Note: In particular, the program is required to ensure that completion of the constructor
of any object of a class type defined in the standard library happens before any other member function
invocation on that object and, unless otherwise specified, to ensure that completion of any member function
invocation other than destruction on such an object happens before destruction of that object. This applies
even to objects such as mutexes intended for thread synchronization. — end note]
If an object of a standard library type is accessed, and the beginning of the object's lifetime
(3.8 [basic.life]) does not happen before the access, or the access does not happen before the end
of the object's lifetime, the behavior is undefined unless otherwise specified. [Note: This applies even to
objects such as mutexes intended for thread synchronization. — end note]
Section: 20.8.2.2.5 [util.smartptr.shared.obs] Status: Tentatively NAD Submitter: Stephan T. Lavavej Opened: 2013-10-05 Last modified: 2015-04-08
View all other issues in [util.smartptr.shared.obs].
View all issues with Tentatively NAD status.
Discussion:
20.8.1.2.4 [unique.ptr.single.observers]/3: "pointer operator->() const noexcept; Requires: get() != nullptr."
20.8.2.2.5 [util.smartptr.shared.obs]/2: "T& operator*() const noexcept; Requires: get() != 0." 20.8.2.2.5 [util.smartptr.shared.obs]/5: "T* operator->() const noexcept; Requires: get() != 0." Narrow-contract functions should not be noexcept.[2014-02-15 Issaquah]
Issue is contentious, raise to P2.
[2015-02 Cologne]
AM: This ship has sailed. JM: What's the issue? AM: operator-> has narrow contract and should never have had noexcept. DK: Not quite. We explicitly called out that for shared_ptr this is fine. You said so in your "narrow contract" paper. GR: This would be a fairly major regression in the design of {unique,shared}_ptr over raw pointers; raw pointer dereferencing is noexcept. It's not a performance regression but a usability regression. AM: Do we expect users to query noexpect on dereference expressions? Room: Yes. VV: We don't just expect it, we have seen it. JM: Yes, users may be querying something like noexcept(x->y) and expect to be checking y, but silently end up checking x->.
Close as NAD, with explanation from GR. Previous resolution [SUPERSEDED]:This wording is relative to N3691.
In 20.8.1.2 [unique.ptr.single]/1, class template unique_ptr synopsis for single objects, change as indicated:
pointer operator->() constnoexcept;In 20.8.1.2.4 [unique.ptr.single.observers] change as indicated:
pointer operator->() constnoexcept;-3- Requires: get() != nullptr.
-4- Returns: get(). -?- Throws: Nothing. -5- Note: use typically requires that T be a complete type.In 20.8.2.2 [util.smartptr.shared]/1, class template shared_ptr synopsis, change as indicated:
T& operator*() constnoexcept; T* operator->() constnoexcept;In 20.8.2.2.5 [util.smartptr.shared.obs] change as indicated:
T& operator*() constnoexcept;-2- Requires: get() != 0.
-3- Returns: *get(). -?- Throws: Nothing. -4- Remarks: When T is void, it is unspecified whether this member function is declared. If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well formed.T* operator->() constnoexcept;-5- Requires: get() != 0.
-6- Returns: get(). -?- Throws: Nothing.
[2015-03-03, Geoffrey provides rationale]
Rationale:
It is by design that these members are noexcept, and changing that now would be a substantial regression in functionality. These classes were designed to substitute for plain pointers as transparently as possible, so since those operations are effectively noexcept on plain pointers, they should be noexcept on unique_ptr and shared_ptr as well. This matters in practice because we expect these members to be used fairly often inside the noexcept operator, and such code could be broken by this change. These design considerations override our general policy against noexcept for narrow-contract functions.
It is notable that N3279, which proposed this policy, did not propose striking noexcept from these operations. It's not clear if the omission of operator* and operator-> was an oversight, or an intentional reflection of the above considerations. N3279 was based on N3248 by the same authors, which states that:"Most applications of noexcept for unique_ptr and shared_ptr are on functions with wide contracts. However, there are preconditions on the atomic access functions, so these should lose the specification."
Proposed resolution: