... на две категории диалектов, одна из которых не подходит для целей, связанных с низкоуровневым программированием, а другая поддерживает только ограниченную оптимизацию. Согласно Обоснованию C, Дух C включает в себя принцип «Не мешайте программисту делать то, что необходимо сделать». Оптимизация, основанная на идее, что программист не будет делать X, полезна только в тех случаях, когда программисту не нужно делать X. К сожалению, большинство аргументов об определенных поведениях полностью теряют это из виду.

ожет удивить некоторых кодеров, и, как ни удивительно, это невозможно реализоватьstd::vector без нестандартной поддержки компиляторов. Проблема, по сути, заключается в способности выполнять арифметику указателей на сырой области хранения. Бумага,p0593: неявное создание объектов для низкоуровневой манипуляции с объектами, который появляется в ответе @ShafikYaghmour, четко обнажает проблему и предлагает модификацию стандарта, чтобы упростить реализацию векторно-подобных контейнеров и других методов программирования на уровне закона.

Тем не менее мне было интересно, если не было работы для реализации типа, эквивалентногоstd::vector использовать только то, что предусмотрено языком, без использования стандартной библиотеки.

Цель состоит в том, чтобы создать векторные элементы, один за другим, в необработанной области хранения и получить доступ к этим элементам с помощью итератора. Это было бы эквивалентно последовательности push_back для std :: vector.

Чтобы получить представление о проблеме, ниже приведено упрощение операций, выполняемых при реализацииstd::vector в libc ++ или libstdc ++:

void access_value(std::string x);

std::string s1, s2, s3;
//allocation
auto p=static_cast<std::string*>(::operator new(10*sizeof(std::string)));

//push_back s1
new(p) std::string(s1);
access_value(*p);//undefined behavior, p is not a pointer to object

//push_back s2
new(p+1) std::string(s2);//undefined behavior
        //, pointer arithmetic but no array (neither implicit array of size 1)
access_value(*(p+1));//undefined behavior, p+1 is not a pointer to object

//push_back s2
new(p+2) std::string(s3);//undefined behavior
        //, pointer arithmetic but no array
access_value(*(p+2));//undefined behavior, p+2 is not a pointer to object

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

//almost trivialy default constructible
template<class T>
union atdc{
  char _c;
  T value;
  atdc ()noexcept{ }
  ~atdc(){}
};

Необработанное хранилище будет инициализировано массивом этого типа объединения, и арифметика указателя всегда выполняется над этим массивом. Затем элементы создаются на неактивном члене объединения при каждом push_back.

std::string s1, s2, s3;
auto p=::operator new(10*sizeof(std::string));
auto arr = new(p) atdc<std::string>[10];
//pointer arithmetic on arr is allowed

//push_back s1
new(&arr[0].value) std::string(s1); //union member activation
access_value(arr[0].value);

//push_back s2
new(&arr[1].value) std::string(s2);
access_value(arr[1].value);

//push_back s2
new(&arr[2].value) std::string(s2);
access_value(arr[2].value);

Есть ли неопределенное поведение в этом коде выше?

Ответы на вопрос(1)

Ваш ответ на вопрос