Используете новое место размещения для обновления ссылочного элемента?

Является ли следующий код допустимым в C ++?

template<typename T>
class Foo {
public:
Foo(T& v) : v_(v) {}

private:
T& v_;
};

int a = 10;
Foo<int> f(a);

void Bar(int& a) {
new (&f)Foo<int>(a);
}

Ссылки не должны быть связаны дважды, верно?

3

Решение

Это совершенно неверно.

[basic.life] / 1, выделение мое:

Время жизни объекта типа T заканчивается, когда:

  • если T тип класса с нетривиальным деструктором (12.4), начинается вызов деструктора, или
  • хранилище, которое занимает объект, используется повторно или освобождается.

Размещение new повторно использует хранилище, заканчивая время жизни объекта, обозначенного f,

[Basic.life] / 7:

Если после окончания срока службы объекта и до хранения
занятый объект используется повторно или освобождается, новый объект
созданный в месте хранения, которое занимал исходный объект,
указатель, указывающий на исходный объект, ссылка, на которую ссылается
к исходному объекту, или имя исходного объекта будет
автоматически ссылаться на новый объект и, по истечении времени жизни
новый объект запущен, может использоваться для манипулирования новым объектом, если:

  • хранилище для нового объекта точно перекрывает место хранения, которое занимал исходный объект, и
  • новый объект того же типа, что и исходный объект (без учета cv-квалификаторов верхнего уровня), и
  • тип исходного объекта не является константно-квалифицированным, и, если тип класса, не содержит какого-либо нестатического члена данных, тип которого
    квалифицированный const или ссылочный тип
    , а также
  • исходный объект был наиболее производным объектом (1.8) типа T и новый объект является наиболее производным объектом типа T (то есть они
    необъекты базового класса).

Поскольку третий пункт пули не выполняется, после звонка Bar, f не относится к объекту, созданному в результате размещения new, но для ранее не существующего объекта, и попытка использовать его приводит к неопределенному поведению.

Смотрите также CWG1776 а также P0137R0.

9

Другие решения

Это может быть законно, но это невероятно плохой стиль. Аргументом для размещения new является void *, поэтому вы говорите C ++ переинтерпретировать_качественный адрес f как void *, а затем используете его как местоположение для создания чего-то нового — перезаписывая исходный f.

По сути, не делай этого.

0

По вопросам рекламы [email protected]