Делать элементы в `std :: array `как член класса по умолчанию инициализируется - PullRequest
1 голос
/ 26 февраля 2020

Рассмотрим:

class x {
    std::array<int, 4> data_;

public:
    x() /*no reference to data_ here*/ {}
};

Обнуляются ли элементы int в data_, или их значение неопределенно?

По расширению это также верно в этом случае:

class x {
    std::variant<std::array<int, 4> /*other stuff here*/> data_;

public:
    x() /*no reference to data here*/ {
        data_.emplace<std::array<int, 4>>(/* no args */);
    }
};

РЕДАКТИРОВАТЬ:

Расширение: есть ли способ получить желаемое поведение из варианта ( не инициализировать данные) .

Если я соединю два примера вместе, я смогу сделать:

struct no_init_array {
     std::array<int, 4> array;
     no_init_array() { } //does nothing
};

class x {
    std::variant<no_init_array/*other stuff here*/> data_;

public:
    x() /*no reference to data here*/ {
        //call default ctor of no_init_array
        //which does not init the std::array (I hope)
        data_.emplace<no_init_array>(/* no args */);
    }
};

1 Ответ

3 голосов
/ 26 февраля 2020

Из документации std::array в разделе конструктора мы можем прочитать:

инициализирует массив в соответствии с правилами агрегированная инициализация ( обратите внимание, что инициализация по умолчанию может привести к неопределенным значениям для некласса T )

выделение шахты

В вашем случае вы имеете std::array<int, 4>. int соответствует определению неклассного типа, поэтому при инициализации по умолчанию содержимое элемента data_ будет иметь неопределенные значения.

Если вы инициализировали элемент data_ как:

std::array<int, 4> data_ {}; // Note the braces

Элементы были бы инициализированы значением, что привело бы к инициализации нуля для int элементов.


Редактировать (из комментариев):

std::variant::emplace() пересылает его аргументы, но, поскольку вы не предоставили никаких аргументов для вставленного std::array<int, 4>, ваш std::variant будет содержать инициализированное значением std::array<int, 4>, поэтому базовые элементы int будет инициализироваться нулями.


Поскольку вам нужен второй вариант использования и вы хотите, чтобы содержимое массива оставалось неинициализированным, вы, конечно, можете сделать то, что вы предложили:

struct X
{
    std::array<int, 4> data_;

    X()
    {}
};
struct Y
{
    std::variant<X, /*...*/> data_ {};

    Y()
    {
        data_.emplace<X>();
    }
};

Живой пример

Но вы должны позаботиться о том, чтобы содержимое массива не было случайно получено до того, как оно позднее будет должным образом инициализировано.

Редактировать:

В После инициализации std::array вы должны убедиться, что она выполняется с помощью ссылки, а не копии массива (чтобы избежать неопределенного поведения при копировании неинициализированных данных).

Например:

Y y;

//X x = std::get<X>(y); // Wrong
X & x = std::get<X>(y); // Right

x.data_[0] = 42;
x.data_[1] = 422;
x.data_[2] = 442;
x.data_[3] = 4422;
...