Re: [v3] More noexcept for vectors
Hi Marc, On 09/15/2013 11:12 AM, Marc Glisse wrote: I had to separate the constructor that takes an allocator from the default constructor in debug/profile, since in release the noexcept only applies to one of them (and the testsuite asserts that release and debug agree on this). An alternative would be to make the release vector default constructor conditionally noexcept (depending on the allocator). Or to use explicit vector(const Allocator = Allocator()); also in normal mode instead of splitting it in two. Thanks a lot. Now I'm wondering if we shouldn't really do the latter: the issue is, if I remember correctly, in C++11, at variance with C++98, allocators aren't necessarily default constructible, thus by explicit instantiatiation the user can easily tell whether that constructor is split or not. What do you think? Paolo.
Re: [v3] More noexcept for vectors
On Mon, 16 Sep 2013, Paolo Carlini wrote: On 09/15/2013 11:12 AM, Marc Glisse wrote: I had to separate the constructor that takes an allocator from the default constructor in debug/profile, since in release the noexcept only applies to one of them (and the testsuite asserts that release and debug agree on this). An alternative would be to make the release vector default constructor conditionally noexcept (depending on the allocator). Or to use explicit vector(const Allocator = Allocator()); also in normal mode instead of splitting it in two. Thanks a lot. Now I'm wondering if we shouldn't really do the latter: the issue is, if I remember correctly, in C++11, at variance with C++98, allocators aren't necessarily default constructible, thus by explicit instantiatiation the user can easily tell whether that constructor is split or not. What do you think? Shouldn't it just be illegal to explicitly instantiate a full class like std::vector? But ok, I'll post that version as soon as I can test it. -- Marc Glisse
Re: [v3] More noexcept for vectors
On 15 September 2013 10:12, Marc Glisse wrote: PR libstdc++/58338 * include/bits/stl_vector.h (_Vector_impl::_Vector_impl(_Tp_alloc_type const), _Vector_impl::_Vector_impl(_Tp_alloc_type), _Vector_impl::_M_swap_data, _Vector_base::_Vector_base(const allocator_type), _Vector_base::_Vector_base(allocator_type), _Vector_base::_Vector_base(_Vector_base), vector::vector(const allocator_type), vector::operator[], vector::operator[] const, vector::front, vector::front const, vector::back, vector::back const, vector::pop_back, vector::_M_erase_at_end): Mark as noexcept. (vector::~vector): Remove useless noexcept. Are you sure the noexcept on the destructors is useless? A user-defined allocator type could have is_nothrow_descructibleallocator_type::value==false or is_nothrow_destructiblepointer::value==false, which would alter the type of is_nothrow_destructiblevectorT, A. Although the user-defined allocator must not actually throw from its destructor, it is not required to have a noexcept destructor. However, since it must not actually throw (irrespective of its exception spec) we can unconditionally give std::vector a noexcept destructor.
Re: [v3] More noexcept for vectors
On Mon, 16 Sep 2013, Jonathan Wakely wrote: Are you sure the noexcept on the destructors is useless? Ok, I am putting it back in. -- Marc Glisse
Re: [v3] More noexcept for vectors
New version that passed testing. 2013-09-16 Marc Glisse marc.gli...@inria.fr PR libstdc++/58338 * include/bits/stl_vector.h (vector::vector(), vector::vector(const allocator_type)): Merge. (_Vector_impl::_Vector_impl(_Tp_alloc_type const), _Vector_impl::_Vector_impl(_Tp_alloc_type), _Vector_impl::_M_swap_data, _Vector_base::_Vector_base(const allocator_type), _Vector_base::_Vector_base(allocator_type), _Vector_base::_Vector_base(_Vector_base), _Vector_base::~_Vector_base, vector::vector(const allocator_type), vector::operator[], vector::operator[] const, vector::front, vector::front const, vector::back, vector::back const, vector::pop_back, vector::_M_erase_at_end): Mark as noexcept. * include/debug/vector (vector::vector(const _Allocator), vector::operator[], vector::operator[] const, vector::front, vector::front const, vector::back, vector::back const, vector::pop_back, _M_requires_reallocation, _M_update_guaranteed_capacity, _M_invalidate_after_nth): Mark as noexcept. * include/profile/vector (vector::vector(const _Allocator), vector::operator[], vector::operator[] const, vector::front, vector::front const, vector::back, vector::back const): Mark as noexcept. (vector::vector(vector, const _Allocator)): Remove wrong noexcept. * testsuite/23_containers/vector/requirements/dr438/assign_neg.cc: Adjust line number. * testsuite/23_containers/vector/requirements/dr438/ constructor_1_neg.cc: Likewise. * testsuite/23_containers/vector/requirements/dr438/ constructor_2_neg.cc: Likewise. * testsuite/23_containers/vector/requirements/dr438/insert_neg.cc: Likewise. -- Marc GlisseIndex: include/bits/stl_vector.h === --- include/bits/stl_vector.h (revision 202625) +++ include/bits/stl_vector.h (working copy) @@ -80,32 +80,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER : public _Tp_alloc_type { pointer _M_start; pointer _M_finish; pointer _M_end_of_storage; _Vector_impl() : _Tp_alloc_type(), _M_start(0), _M_finish(0), _M_end_of_storage(0) { } - _Vector_impl(_Tp_alloc_type const __a) + _Vector_impl(_Tp_alloc_type const __a) _GLIBCXX_NOEXCEPT : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0) { } #if __cplusplus = 201103L - _Vector_impl(_Tp_alloc_type __a) + _Vector_impl(_Tp_alloc_type __a) noexcept : _Tp_alloc_type(std::move(__a)), _M_start(0), _M_finish(0), _M_end_of_storage(0) { } #endif - void _M_swap_data(_Vector_impl __x) + void _M_swap_data(_Vector_impl __x) _GLIBCXX_NOEXCEPT { std::swap(_M_start, __x._M_start); std::swap(_M_finish, __x._M_finish); std::swap(_M_end_of_storage, __x._M_end_of_storage); } }; public: typedef _Alloc allocator_type; @@ -117,53 +117,53 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT { return *static_castconst _Tp_alloc_type*(this-_M_impl); } allocator_type get_allocator() const _GLIBCXX_NOEXCEPT { return allocator_type(_M_get_Tp_allocator()); } _Vector_base() : _M_impl() { } - _Vector_base(const allocator_type __a) + _Vector_base(const allocator_type __a) _GLIBCXX_NOEXCEPT : _M_impl(__a) { } _Vector_base(size_t __n) : _M_impl() { _M_create_storage(__n); } _Vector_base(size_t __n, const allocator_type __a) : _M_impl(__a) { _M_create_storage(__n); } #if __cplusplus = 201103L - _Vector_base(_Tp_alloc_type __a) + _Vector_base(_Tp_alloc_type __a) noexcept : _M_impl(std::move(__a)) { } - _Vector_base(_Vector_base __x) + _Vector_base(_Vector_base __x) noexcept : _M_impl(std::move(__x._M_get_Tp_allocator())) { this-_M_impl._M_swap_data(__x._M_impl); } _Vector_base(_Vector_base __x, const allocator_type __a) : _M_impl(__a) { if (__x.get_allocator() == __a) this-_M_impl._M_swap_data(__x._M_impl); else { size_t __n = __x._M_impl._M_finish - __x._M_impl._M_start; _M_create_storage(__n); } } #endif - ~_Vector_base() + ~_Vector_base() _GLIBCXX_NOEXCEPT { _M_deallocate(this-_M_impl._M_start, this-_M_impl._M_end_of_storage - this-_M_impl._M_start); } public: _Vector_impl _M_impl; pointer _M_allocate(size_t __n) { return __n != 0 ? _M_impl.allocate(__n) : 0; } @@ -236,31 +236,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER protected: using _Base::_M_allocate; using
Re: [v3] More noexcept for vectors
On 09/16/2013 07:32 PM, Marc Glisse wrote: New version that passed testing. Looks good to me, thanks! Paolo.
Re: [v3] More noexcept for vectors
I had to separate the constructor that takes an allocator from the default constructor in debug/profile, since in release the noexcept only applies to one of them (and the testsuite asserts that release and debug agree on this). An alternative would be to make the release vector default constructor conditionally noexcept (depending on the allocator). Or to use explicit vector(const Allocator = Allocator()); also in normal mode instead of splitting it in two. I also removed a noexcept in profile mode where the release mode doesn't have noexcept. Tested, no regression. 2013-09-15 Marc Glisse marc.gli...@inria.fr PR libstdc++/58338 * include/bits/stl_vector.h (_Vector_impl::_Vector_impl(_Tp_alloc_type const), _Vector_impl::_Vector_impl(_Tp_alloc_type), _Vector_impl::_M_swap_data, _Vector_base::_Vector_base(const allocator_type), _Vector_base::_Vector_base(allocator_type), _Vector_base::_Vector_base(_Vector_base), vector::vector(const allocator_type), vector::operator[], vector::operator[] const, vector::front, vector::front const, vector::back, vector::back const, vector::pop_back, vector::_M_erase_at_end): Mark as noexcept. (vector::~vector): Remove useless noexcept. * include/debug/vector (vector::vector()): Split. (vector::vector(const _Allocator), vector::operator[], vector::operator[] const, vector::front, vector::front const, vector::back, vector::back const, vector::pop_back, _M_requires_reallocation, _M_update_guaranteed_capacity, _M_invalidate_after_nth): Mark as noexcept. (vector::~vector): Remove useless noexcept. * include/profile/vector (vector::vector()): Split. (vector::vector(const _Allocator), vector::operator[], vector::operator[] const, vector::front, vector::front const, vector::back, vector::back const): Mark as noexcept. (vector::vector(vector, const _Allocator)): Remove wrong noexcept. (vector::~vector): Remove useless noexcept. -- Marc GlisseIndex: include/bits/stl_vector.h === --- include/bits/stl_vector.h (revision 202588) +++ include/bits/stl_vector.h (working copy) @@ -80,32 +80,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER : public _Tp_alloc_type { pointer _M_start; pointer _M_finish; pointer _M_end_of_storage; _Vector_impl() : _Tp_alloc_type(), _M_start(0), _M_finish(0), _M_end_of_storage(0) { } - _Vector_impl(_Tp_alloc_type const __a) + _Vector_impl(_Tp_alloc_type const __a) _GLIBCXX_NOEXCEPT : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0) { } #if __cplusplus = 201103L - _Vector_impl(_Tp_alloc_type __a) + _Vector_impl(_Tp_alloc_type __a) noexcept : _Tp_alloc_type(std::move(__a)), _M_start(0), _M_finish(0), _M_end_of_storage(0) { } #endif - void _M_swap_data(_Vector_impl __x) + void _M_swap_data(_Vector_impl __x) _GLIBCXX_NOEXCEPT { std::swap(_M_start, __x._M_start); std::swap(_M_finish, __x._M_finish); std::swap(_M_end_of_storage, __x._M_end_of_storage); } }; public: typedef _Alloc allocator_type; @@ -117,36 +117,36 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT { return *static_castconst _Tp_alloc_type*(this-_M_impl); } allocator_type get_allocator() const _GLIBCXX_NOEXCEPT { return allocator_type(_M_get_Tp_allocator()); } _Vector_base() : _M_impl() { } - _Vector_base(const allocator_type __a) + _Vector_base(const allocator_type __a) _GLIBCXX_NOEXCEPT : _M_impl(__a) { } _Vector_base(size_t __n) : _M_impl() { _M_create_storage(__n); } _Vector_base(size_t __n, const allocator_type __a) : _M_impl(__a) { _M_create_storage(__n); } #if __cplusplus = 201103L - _Vector_base(_Tp_alloc_type __a) + _Vector_base(_Tp_alloc_type __a) noexcept : _M_impl(std::move(__a)) { } - _Vector_base(_Vector_base __x) + _Vector_base(_Vector_base __x) noexcept : _M_impl(std::move(__x._M_get_Tp_allocator())) { this-_M_impl._M_swap_data(__x._M_impl); } _Vector_base(_Vector_base __x, const allocator_type __a) : _M_impl(__a) { if (__x.get_allocator() == __a) this-_M_impl._M_swap_data(__x._M_impl); else { @@ -246,21 +246,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * @brief Default constructor creates no elements. */ vector() : _Base() { } /** * @brief Creates a %vector with no elements. * @param __a An allocator object. */ explicit - vector(const
[v3] More noexcept for vectors
Hello, this patch passes bootstrap+testsuite. The guarantees given by the standard on allocators are a bit weird, but I see there is already DR2016 taking care of it. 2013-09-14 Marc Glisse marc.gli...@inria.fr PR libstdc++/58338 * include/bits/stl_vector.h (_Vector_impl::_Vector_impl(_Tp_alloc_type const), _Vector_impl::_Vector_impl(_Tp_alloc_type), _Vector_impl::_M_swap_data, _Vector_base::_Vector_base(const allocator_type), _Vector_base::_Vector_base(allocator_type), _Vector_base::_Vector_base(_Vector_base), vector::vector(const allocator_type), vector::operator[], vector::operator[] const, vector::front, vector::front const, vector::back, vector::back const, vector::pop_back, vector::_M_erase_at_end): Mark as noexcept. (vector::~vector): Remove useless noexcept. -- Marc GlisseIndex: include/bits/stl_vector.h === --- include/bits/stl_vector.h (revision 202588) +++ include/bits/stl_vector.h (working copy) @@ -80,32 +80,32 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER : public _Tp_alloc_type { pointer _M_start; pointer _M_finish; pointer _M_end_of_storage; _Vector_impl() : _Tp_alloc_type(), _M_start(0), _M_finish(0), _M_end_of_storage(0) { } - _Vector_impl(_Tp_alloc_type const __a) + _Vector_impl(_Tp_alloc_type const __a) _GLIBCXX_NOEXCEPT : _Tp_alloc_type(__a), _M_start(0), _M_finish(0), _M_end_of_storage(0) { } #if __cplusplus = 201103L - _Vector_impl(_Tp_alloc_type __a) + _Vector_impl(_Tp_alloc_type __a) noexcept : _Tp_alloc_type(std::move(__a)), _M_start(0), _M_finish(0), _M_end_of_storage(0) { } #endif - void _M_swap_data(_Vector_impl __x) + void _M_swap_data(_Vector_impl __x) _GLIBCXX_NOEXCEPT { std::swap(_M_start, __x._M_start); std::swap(_M_finish, __x._M_finish); std::swap(_M_end_of_storage, __x._M_end_of_storage); } }; public: typedef _Alloc allocator_type; @@ -117,36 +117,36 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT { return *static_castconst _Tp_alloc_type*(this-_M_impl); } allocator_type get_allocator() const _GLIBCXX_NOEXCEPT { return allocator_type(_M_get_Tp_allocator()); } _Vector_base() : _M_impl() { } - _Vector_base(const allocator_type __a) + _Vector_base(const allocator_type __a) _GLIBCXX_NOEXCEPT : _M_impl(__a) { } _Vector_base(size_t __n) : _M_impl() { _M_create_storage(__n); } _Vector_base(size_t __n, const allocator_type __a) : _M_impl(__a) { _M_create_storage(__n); } #if __cplusplus = 201103L - _Vector_base(_Tp_alloc_type __a) + _Vector_base(_Tp_alloc_type __a) noexcept : _M_impl(std::move(__a)) { } - _Vector_base(_Vector_base __x) + _Vector_base(_Vector_base __x) noexcept : _M_impl(std::move(__x._M_get_Tp_allocator())) { this-_M_impl._M_swap_data(__x._M_impl); } _Vector_base(_Vector_base __x, const allocator_type __a) : _M_impl(__a) { if (__x.get_allocator() == __a) this-_M_impl._M_swap_data(__x._M_impl); else { @@ -246,21 +246,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * @brief Default constructor creates no elements. */ vector() : _Base() { } /** * @brief Creates a %vector with no elements. * @param __a An allocator object. */ explicit - vector(const allocator_type __a) + vector(const allocator_type __a) _GLIBCXX_NOEXCEPT : _Base(__a) { } #if __cplusplus = 201103L /** * @brief Creates a %vector with default constructed elements. * @param __n The number of elements to initially create. * @param __a An allocator. * * This constructor fills the %vector with @a __n default * constructed elements. @@ -404,21 +404,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_initialize_dispatch(__first, __last, _Integral()); } #endif /** * The dtor only erases the elements, and note that if the * elements themselves are pointers, the pointed-to memory is * not touched in any way. Managing the pointer is the user's * responsibility. */ - ~vector() _GLIBCXX_NOEXCEPT + ~vector() { std::_Destroy(this-_M_impl._M_start, this-_M_impl._M_finish, _M_get_Tp_allocator()); } /** * @brief %Vector assignment operator. * @param __x A %vector of identical element and allocator types. * * All the elements of @a __x are copied, but any extra memory in
Re: [v3] More noexcept for vectors
Hi, Marc Glisse marc.gli...@inria.fr ha scritto: Hello, this patch passes bootstrap+testsuite. The guarantees given by the standard on allocators are a bit weird, but I see there is already DR2016 taking care of it. Patch looks good to me, thanks! Paolo
Re: [v3] More noexcept for vectors
... what about debug-mode (and profile-mode)? Is in principle possible to detect the noexcepts? If we can't exclude that, we should probably change at the same time the special modes too. Otherwise seems just matter of consistency? Paolo
Re: [v3] More noexcept for vectors
On Sat, 14 Sep 2013, Paolo Carlini wrote: ... what about debug-mode (and profile-mode)? Is in principle possible to detect the noexcepts? If we can't exclude that, we should probably change at the same time the special modes too. Otherwise seems just matter of consistency? I was going one file at a time, and the priority is clearly release-mode, since this is about performance. I don't think there is anything wrong with debug-mode having a different exception specification (it is already binary-incompatible with the default mode) but I understand why people may want to keep some consistency. I can do vector in the other modes next if you want. -- Marc Glisse
Re: [v3] More noexcept for vectors
Hi, I was going one file at a time, and the priority is clearly release-mode, since this is about performance. I don't think there is anything wrong with debug-mode having a different exception specification (it is already binary-incompatible with the default mode) but I understand why people may want to keep some consistency. I can do vector in the other modes next if you want. Yes, please. As boring as it may seem, I'm trying to convince myself and the other contributors to keep the modes up to date and consistent as much as possible. If one day we figure out that we can't, we don't have enough man power it will mean we have to remove the special modes (or only some of them) from svn. Thanks! Paolo