Нарушение константной корректности [новое размещение] и неопределенное поведение

Я прочитал следующее: Размещение новых разрывов, констант и ссылок? и, прочитав слайды Маттиса Круза на C ++ Meeting, я запутался относительно следующего кода

struct U { const int i; };
std::vector<U> B;
B.push_back({ 1 });
B.clear();
B.push_back({ 2 });
const int v = B[0].i; // <- Undefined Behavior

B.clear() только разрушает объекты, а B.push_back({2}) использует размещение new для создания нового объекта в начале области памяти, выделенной B.

  1. Я не совсем понимаю, почему доступ B[0].i является неопределенным поведением.
  2. Мог ли компилятор кэшировать B[0].i и, возможно, вывести 1?
  3. При чем здесь std :: launder? Действительно ли это инструмент, позволяющий убедиться, что такая оптимизация компилятора невозможна?

Стандартная реализация libcxx [llvm]:

template <class Tp, class Allocator>
inline typename vector<Tp, Allocator>::reference
vector<Tp, Allocator>::operator[](size_type n)
{
   assert(n < size(), "vector[] index out of bounds");
    return this->__begin_[n];
}

такое же, как на слайдах.

Ссылки с std 2017:

  • 8.3 (возможное нарушение)
  • 8.4 (упоминание std :: launder)

person Gabriel    schedule 28.11.2018    source источник
comment
Это похоже на дубликат Как std :: launder влияет на контейнеры?.   -  person ShadowRanger    schedule 29.11.2018
comment
Мой ответ на Реализация контейнера типа std :: vector без неопределенного поведения может объяснить некоторые детали.   -  person Shafik Yaghmour    schedule 29.11.2018