diff mbox

Default std::vector<bool> default and move constructor

Message ID b580bfe8-adef-1926-7b2b-2a6a6ca478cf@gmail.com
State New
Headers show

Commit Message

François Dumont May 28, 2017, 8:13 p.m. UTC
On 27/05/2017 13:14, Jonathan Wakely wrote:
> On 26/05/17 23:13 +0200, François Dumont wrote:
>> On 25/05/2017 18:28, Jonathan Wakely wrote:
>>> On 15/05/17 19:57 +0200, François Dumont wrote:
>>>> Hi
>>>>
>>>>   Following what I have started on RbTree here is a patch to 
>>>> default implementation of default and move constructors on 
>>>> std::vector<bool>.
>>>>
>>>>   As in _Rb_tree_impl the default allocator is not value 
>>>> initialized anymore. We could add a small helper type arround the 
>>>> allocator to do this value initialization per default. Should I do 
>>>> so ?
>>>
>>> It's required to be value-initialized, so if your patch changes that
>>> then it's a problem.
>>>
>>> Did we decide it's OK to do that for RB-trees? Did we actually discuss
>>> that part of the r243379 changes?
>>
>> I remember a message pointing this issue but after the commit AFAIR. 
>> I thought it was from Tim but I can't find it on the archive.
>>
>> What is the rational of this requirement ? I started working on a 
>> type to do the allocator value initialization if there is no default 
>> constructor but it seems quite complicated to do so. It is quite sad 
>> that we can't fully benefit from this nice C++11 feature just because 
>> of this requirement. If there is any initialization needed it doesn't 
>> sound complicated to provide a default constructor.
>
> The standard says that the default constructor is:
>
>  vector() : vector(Allocator()) { }
>
> That value-initializes the allocator. If the allocator type behaves
> differently for value-init and default-init (e.g. it has data members
> that are left uninitialized by default-init) then the difference
> matters. If you change the code so it only does default-init of the
> allocator then you will introduce an observable difference.
>
> I don't see any requirement that a DefaultConstructible allocator
> cannot leave members uninitialized, so that means the standard
> requires default construction of vector<bool> to value-init the
> allocator. Not default-init.

Sure but like freedom which stop where start others' freedom so does 
those requirements :-). Because the Standard says that an allocator will 
be value-init when there is no default-init it makes usage of the C++11 
default constructor more complicated.

But as it is unavoidable here is a type I tried to work on to keep 
current implementations as long as we inherit from 
__alloc_value_initializer.

I don't like it myself but I propose just in case you are interested.

Otherwise I am also going to rework my patch to keep this initialization.

François

Comments

Jonathan Wakely May 31, 2017, 10:37 a.m. UTC | #1
On 28/05/17 22:13 +0200, François Dumont wrote:
>Sure but like freedom which stop where start others' freedom so does 
>those requirements :-). Because the Standard says that an allocator 
>will be value-init when there is no default-init it makes usage of the 
>C++11 default constructor more complicated.

It makes the std::lib implementors job harder, for the benefit of
users. That is the correct trade off.

We don't get to ignore the guarantees of the standard just because
they're difficult.
diff mbox

Patch

diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h
index 2081386..9e8afed 100644
--- a/libstdc++-v3/include/bits/allocator.h
+++ b/libstdc++-v3/include/bits/allocator.h
@@ -241,6 +241,52 @@  _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 #endif
 
+  template<typename _Alloc, bool
+	   = !__is_empty(_Alloc) && __is_trivial(_Alloc)>
+    struct __alloc_value_initializer;
+
+  template<typename _Alloc>
+    struct __alloc_value_initializer<_Alloc, true> : public _Alloc
+    {
+      // Explicit value initialization.
+      __alloc_value_initializer() _GLIBCXX_USE_NOEXCEPT
+	: _Alloc()
+      { }
+
+      __alloc_value_initializer(const _Alloc& __other)
+	_GLIBCXX_NOEXCEPT_IF( noexcept(_Alloc(__other)) )
+	: _Alloc(__other)
+      { }
+
+#if __cplusplus >= 201103L
+      __alloc_value_initializer(_Alloc&& __other)
+	noexcept( noexcept(_Alloc(std::move(__other))) )
+	: _Alloc(std::move(__other))
+      { }
+#endif
+    };
+
+  template<typename _Alloc>
+    struct __alloc_value_initializer<_Alloc, false> : public _Alloc
+    {
+#if __cplusplus >= 201103L
+      __alloc_value_initializer() = default;
+
+      __alloc_value_initializer(_Alloc&& __other)
+	noexcept( noexcept(_Alloc(std::move(__other))) )
+	: _Alloc(std::move(__other))
+      { }
+#else
+      __alloc_value_initializer() throw()
+      { }
+#endif
+
+      __alloc_value_initializer(const _Alloc& __other)
+	_GLIBCXX_NOEXCEPT_IF(noexcept(_Alloc(__other)))
+	: _Alloc(__other)
+      { }
+    };
+
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std