C++ Logo

std-proposals

Advanced search

initializer_list vs. move semantics breaks uniform initialization

From: Marc Mutz <marc.mutz_at_[hidden]>
Date: Fri, 15 Nov 2019 20:58:47 +0100
Hi,

Consider

    std::vector<std::unique_ptr<Widget>> v = {
        std::make_unique<Widget>(1),
        std::make_unique<Widget>(2),
    }; // ERROR: call to deleted copy ctor requested

which doesn't work because unique_ptr isn't copyable.

This is unfortunate, because the following works as expected:

    std::unique_ptr<Widget> v[] = {
        std::make_unique<Widget>(1),
        std::make_unique<Widget>(2),
    }; // OK

We're therefore back in a situation where std::vector cannot be
initialized like a C array, something we wanted to fix with
initializer_list.

The design paper for initializer_list, wg21.link/N2215 has an example,
in the Q&A section, describing a scenario where modification of an
initializer_list's elements might backfire:

    int f() {
        Odd_vector<int> = {1, 2, 3};
        return v[0];
    };
    f();
    f();
    f();

If Odd_vector's ctor changed the first element in the initializer_list,
then subsequent calls to f() would produce different values.

However, the final wording, wg21.link/N2675, binds the lifetime of the
implicit array to the lifetime of the initializer_object:

> The lifetime of the array is the same as that of the initializer_list
> object.

By this token, the array needs to be re-created for each invocation of
f() (though there's an escape hatch by which compilers are allowed to
store the array in read-only memory, too).

I presume the paper has been written pre-move-semantics.

Have there been attempts since to reconcile move semantics and
initializer_list? Pointers welcome.

Thanks,
Marc

Received on 2019-11-15 14:01:09