This is the mail archive of the
libstdc++@gcc.gnu.org
mailing list for the libstdc++ project.
Re: Failing test when run as C++11
- From: Jonathan Wakely <jwakely at redhat dot com>
- To: Daniel Krügler <daniel dot kruegler at gmail dot com>
- Cc: libstdc++ <libstdc++ at gcc dot gnu dot org>
- Date: Fri, 9 May 2014 12:31:16 +0100
- Subject: Re: Failing test when run as C++11
- Authentication-results: sourceware.org; auth=none
- References: <20140509105321 dot GD10556 at redhat dot com> <CAGNvRgBEuc1qSiPA41-AiVifoW0aLXYVwQZK+O-SiODxauQDew at mail dot gmail dot com> <20140509112018 dot GE10556 at redhat dot com>
On 09/05/14 12:20 +0100, Jonathan Wakely wrote:
On 09/05/14 13:15 +0200, Daniel Krügler wrote:
2014-05-09 12:53 GMT+02:00 Jonathan Wakely <jwakely@redhat.com>:
20_util/specialized_algorithms/uninitialized_copy/808590.cc fails if
run in C++11 mode because is_nothrow_move_constructible<c> is false,
which means vector::resize() copies the elements using non-const
lvalue arguments, which selects the template constructor.
(In C++03 it copies from *const* lvalue arguments, selecting the copy
constructor.)
We can either fix it by adding throw() to the copy constructor, or by
adding a move cosntructor (with a comment explaining why):
#if __cplusplus >= 201103L
c(c&&) = default;
#endif
I can't decide which I prefer, does anyone else have a preference?
Do you know whether the test case was added to validate a bug fix and
if so, which one? I would like to ensure that the change still
reflects the original intention for adding it.
See https://bugzilla.redhat.com/show_bug.cgi?id=808590
That was filed against Red Hat's GCC 4.4 and at the time the upstream
GCC already passed the test. Benjamin added the test to catch any
regressions. Arguably, the C++11 behaviour (copying from non-const
lvalue instead of const lvalue) can be considered a regression, but I
think it's the correct behaviour.
To explain why I think it's correct...
In C++03 the vector::resize() copied objects via (the equivalent of)
allocator<c>::construct(pointer, const c&) which always calls the
copy constructor, c::c(const c&).
In C++11 it uses the allocator_traits equivalent of
allocator<c>::construct(pointer, Args&&...) which can call any
constructor, depending on the value category, cv-qualification and
type of the argument. When is_nothrow_move_constructible<c> is false
(as in the current test code) the argument is an lvalue, so we call
c::c<c>(c&) instead of c::c(const c&).
If is_nothrow_move_constructible<c> was true then the argument would
be forwarded as an rvalue, so the template constructor isn't viable
and we would call c::c(const c&), or c::c(c&&) if we add that.