C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Proposal for skipping initialization in vector and complex constructors

From: André Offringa <offringa_at_[hidden]>
Date: Sun, 10 Nov 2024 13:59:26 +0100
On 10/11/2024 12:29, Bo Persson via Std-Proposals wrote:
> On 2024-11-10 at 11:04, André Offringa via Std-Proposals wrote:
>> [..]
>> // Add n uninitialized values at the given position
>> // (maybe too obscure...)
>> iterator insert(const_iterator position, size_t n,
>> skip_initialization_t)
>>
>
> Yes, very obscure. This sounds like a footgun fully loaded.

I don't disagree -- it's the constructors I find most important.
Thinking about insert() was just out of interest ;).

> At least it has to be restricted on what types it can be used for,
> which makes it even more of a niche feature.

Restricting the type could be a good starting point, but I would
question if you should in the end. The UVector implementation I talked
about was initially restricted to use trivial types, but I found use for
it in different types as well. One was that if I wanted to create a
vector of uninitialized Complex values (where Complex is my 'own'
complex type with tag constructor), I could do this:

   UVector<Complex<double>> vector(n, skip_initialization);
   for(size_t i=0; i!=n; ++i) {
     new(&vector.data()[i]) Complex<double>(skip_initialization);
   }

This produces a vector of uninitialized Complex values, so without any
zero initialization. Of course this could be done easier if I had made
my default constructor of Complex uninitialized, but this isn't possible
for Complex (or std::complex) to keep it's interface the same. It's
certainly also obscure (e.g. I didn't use a ranged for because I wasn't
sure that doing that over an uninitialized type is possible), but it's
so far the best solution I have to do this, and I need this
functionality not uncommonly.

( The loop is only to tell the compiler there are constructed objects
there, which I think is required to avoid undefined behaviour when using
the elements of vector, but from the assembly it seems to compile to
nothing. )

> Just consider if someone tries this on a vector<string> and then,
> somewhere else in the program, there is an exception thrown. What
> happens to a vector of undestructible objects? Or if, by a slight
> mistake, the vector is resized again before all the objects have been
> constructed?

Yeah those are good questions. I can agree we should minimize the
possibility for errors, but clearly in this regime it won't be possible
to make everything safe.

> If someone tries this on a vector<string> and then, somewhere else in
the program, there is an exception thrown
is there any other option then making this undefined behaviour?

> What happens to a vector of undestructible objects?
I think the current state is that objects with deleted destructors can't
be stored at all in a vector... That seems a good starting point to
continue with. It could be changed to make it possible to allow
constructing the vector but any operation that would destruct it does
not compile, but I don't know if that's important.

> Or if, by a slight mistake, the vector is resized again before all
the objects have been constructed?
Imho this can be most easily set to undefined behaviour for non-trivial
types. Since any read after uninitialized construction is undefined
behaviour, this includes that.

Regards,
André

Received on 2024-11-10 12:59:29