Приводит ли наличие вектора, содержащего структуры с неинициализированными членами, к неопределенному поведению?

Если у вас есть вектор, содержащий структуры с неинициализированными членами, является ли это неопределенным поведением. Контекстом для этого является вектор, который создается, но затем заполняется в параллельном контексте. Таким образом, инициализация вектора по умолчанию теряется.

Пример

template< typename T >
struct uninitialized
{
    T t;
    uninitialized(){};
    uninitialized & operator=( T const & inT ){ t = inT             ; return *this; }
    uninitialized & operator=( T      && inT ){ t = std::move( inT ); return *this; }
};

std::vector< uninitialized< int > > example()
{
    auto vector = std::vector< uninitialized< int > >(500);

    // Other code unrelated to vector

    for( auto & element : vector ) element = 0; // For loop as stand in for potentially parallel context
    // "0" is simply used as a stand in to keep the example simple

    // Code which might use vector

    return vector;
}

Стоит отметить, что неинициализированные члены никогда не будут прочитаны до того, как они в конечном итоге будут инициализированы.

Если это имеет значение для ответа, предполагается использование простых числовых типов, таких как int, или агрегатных типов, состоящих из этих числовых типов.

(Также, чтобы избежать ненужных комментариев, reserve + push_back здесь неуместно, поскольку важен окончательный порядок вектора)

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
73
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В опубликованном коде нет неопределенного поведения (UB):

  • Создание vector с 500 элементами — это нормально:

    auto vector = std::vector<uninitialized<int>>(500);
    

    Все элементы будут созданы с помощью конструктора uninitialized по умолчанию. Тот факт, что он не инициализируется T t, здесь не имеет значения.

  • Цикл с присваиваниями тоже в порядке:

    for( auto & element : vector ) element = 0;
    

    Все элементы будут назначены через uninitialized::operator=(T const & inT ), а их T t будет установлен в 0.

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

Просто из любопытства: что, если элемент отодвинут назад и необходимо перераспределение до инициализации векторных элементов? Будет ли это неопределенным поведением? На этом этапе существующие неинициализированные элементы должны быть скопированы в новое место и, следовательно, должны быть прочитаны.

j6t 03.07.2024 11:44

@j6t интересно. Я думаю, у вас есть точка зрения (но она не имеет отношения к опубликованному коду ОП).

wohlstad 03.07.2024 11:46

В вашем коде нет UB, поскольку перед доступом к элементу данных вы назначаете его в цикле for.

Вы можете упростить свой код и сделать его еще более компактным, добавив параметризованный ctor. Таким образом, вам вообще не придется использовать цикл for для присваивания, и вы сможете просто инициализировать vector напрямую при его определении, как показано ниже.

template< typename T >
struct uninitialized
{
    T t;
    uninitialized(){};
    uninitialized & operator=( T const & inT ){ t = inT             ; return *this; }
    uninitialized & operator=( T      && inT ){ t = std::move( inT ); return *this; }
    //parameterized ctor added
    uninitialized(T t_): t(t_){} 
};
std::vector< uninitialized< int > > example()
{
    //directly initalized vector 
    std::vector< uninitialized< int > > vectorobj(500, 0); 
  
    //no need for for loop here anymore
    return vectorobj;
}

Другие вопросы по теме