问题
Reading this and this and 23.3.6.5/1 of the standard, where in the latest C++ standard draft is it specified that implementers should prioritize the use of non-throwing move-constructor T(T &&t) noexcept
over a const copy-constructor T(const T &t)
when std::vector<T>
re-allocates its element as a result of a push_back
operation? Is it 13.3.3.1.4/1 on overload resolution of reference binding?
EDIT 1
I argue on 13.3.3.1.4/1 because of the following reasons:
- 13.3/2
Overload resolution selects the function to call in seven distinct contexts within the language. [...] invocation of a constructor for direct-initialization (8.5) of a class object (13.3.1.3); [...] Each of these contexts defines the set of candidate functions and the list of arguments in its own unique way. But, once the candidate functions and argument lists have been identified, the selection of the best function is the same in all cases: First, a subset of the candidate functions (those that have the proper number of arguments and meet certain other conditions) is selected to form a set of viable functions (13.3.2). Then the best viable function is selected based on the implicit conversion sequences (13.3.3.1) needed to match each argument to the corresponding parameter of each viable function.
- 13.3.2/1
From the set of candidate functions constructed for a given context (13.3.1), a set of viable functions is chosen, from which the best function will be selected by comparing argument conversion sequences for the best fit (13.3.3). The selection of viable functions considers relationships between arguments and function parameters other than the ranking of conversion sequences.
- 13.3.1.3/1
When objects of class type are direct-initialized (8.5), or copy-initialized from an expression of the same or a derived class type (8.5), overload resolution selects the constructor.
- 13.3.3.1/5
For the case where the parameter type is a reference, see 13.3.3.1.4.
- 13.3.3.1.4/1
When a parameter of reference type binds directly (8.5.3) to an argument expression, the implicit conversion sequence is the identity conversion, [...]
And therefore, I conclude that the requirement of identity conversion results in requiring the prioritization of T(T &&t) noexcept
over T(const T &t)
. But, the other party I am arguing with is not convinced. So, I ask here.
EDIT 2
The following is the link between 23.3.6.5 and 13.3.3.1.4:
First, 23.3.6.5 requires the following of std::vector
:
[...]
void push_back(const T& x);
void push_back(T&& x);
Remarks: [...] If an exception is thrown other than by the copy constructor, move constructor, assignment operator, or move assignment operator of T or by any InputIterator operation there are no effects. [...]
That is covered by 23.3.6.1/2 that requires the following:
A vector satisfies all of the requirements of a container and of a reversible container (given in two tables in 23.2), [...]
That is, std::vector
is expected to comply with 23.2.1/7 that specifies the following:
Unless otherwise specified, all containers defined in this clause obtain memory using an allocator (see 17.6.3.5).
and with 23.2.1/3 that specifies the following:
For the components affected by this subclause that declare an
allocator_type
, objects stored in these components shall be constructed using theallocator_traits<allocator_type>::construct
function and destroyed using the allocator_traits<allocator_type>::destroy function (20.7.8.2). These functions are called only for the container’s element type, not for internal types used by the container.
Since 20.7.8.2 specifies only one construct
function as follows:
template <class T, class... Args>
static void construct(Alloc& a, T* p, Args&&... args);
with 20.7.8.2/5 requiring the following:
Effects: calls
a.construct(p, std::forward<Args>(args)...)
if that call is well-formed; otherwise, invokes::new (static_cast<void*>(p)) T(std::forward<Args>(args)...)
.
and 20.7.9.2/12 requiring the following of the default allocator:
Effects:
::new((void *)p) U(std::forward<Args>(args)...)
, both T(std::forward<Args>(args)...)
in 20.7.8.2/5 and U(std::forward<Args>(args)...)
in 20.7.9.2/12 will follow the constructor overload resolution requirement in 13.3.3.1.4/1.
The standard therefore requires the implementers to prioritize the use of move-constructor T(T &&t) noexcept
over copy-constructor T(const T &t)
when std::vector<T>
re-allocates its elements due to push_back
operations.
来源:https://stackoverflow.com/questions/46409188/does-c11-standard-require-implementers-to-prioritize-noexcept-move-constructor