"По честному" это писать VTBL руками. С сигнатурами функций типа doIt(Data* _this, ) и пр.
В итоге получишь то что компилятор C++ и так делает, как ты сам сказал когда-то.
Вот про это
Base t(std::move(b));
Derived* d = new(&b)Derived(std::move(t));
я думал. Попробуй в members описать std::string поле.
Короче вместо Base(NO_INIT) конструкторов тебе нужно будет писать Base(Base &&moved) конструкторы. Ровно столько же.
И это всегда будет требовать temporary при конвертации и ненулевой CPU penalty.
Re[6]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, jazzer, Вы писали:
J>Здравствуйте, c-smile, Вы писали:
CS>>>>Вызвать placement new без вызова конструктора.
J>>>placement new без вызова конструктора называется reinterpret_cast
CS>>Ну нет конечно. placement new как минимум инициализирует vtbl если она есть. reinterpret_cast он ничего не делает. Или я не понял сермяжность.
J>Это делает конструктор. Вернее, стандарт не специфицирует vtbl вообще, но по сути этим занимается конструктор в качестве первого шага, так как указатель на vtbl — это просто скрытый член, который надо проинициализировать.
Это происходит между new и первым конструктором. Но это не суть важно.
J>Так что сермяжность очень простая: new выделяет память, вызывает конструктор, возвращает указатель нужного типа. J>placement new убирает первый шаг, оставляя вызов конструктора и возврат указателя нужного типа. J>Если ты убираешь и конструктор, остается просто возврат указателя — это reinterpret_cast.
Ну ок. "Рука бога" вставляет vtbl pointer.
Для простоты будем считать что кроме VTBL никакой другой практической имплементации виртуальности нам не известно.
Во всяком случае для всех компиляторов поддерживающих COM и CORBA объекты из коробки это именно VTBL и ничто другое.
J>>>Для произвольного левого класса это невозможно сделать, если ты хочешь, чтоб код оставался соответствующим Стандарту. Если классы все под твоим контролем — юзай указатель pimpl, в него ты можешь засунуть все, что угодно (в т.ч. std::string), и не инициализировать, если он уже есть (ну или передавать указатель в конструктор, чтоб уж совсем не зависеть от его точного расположения в классе).
Ищется решение которое вводит наиментшее кол-во сущностей и CPU penalty.
J>Но если ты хочешь пользоваться встроенной системой типов С++ в соответствии со стандартом — придется соответствовать, не предполагая, в частности, никаких vtbl и прочего.
Странно, все говорят про Стандарт, но никто так конкретно и не говорит чем мое решение его нарушает.
Вообще какая-то странная ситуация получается. С одной стороны использование reinterpret_cast конструкций типа как легитимно в C++.
А с другой стороны вариация оного так сразу супротив Стандарта.
Re[7]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, c-smile, Вы писали: К>>А если не выклёвывать себе мозг всякими трюками, и сделать по-честному: CS>"По честному" это писать VTBL руками. С сигнатурами функций типа doIt(Data* _this, ) и пр. CS>В итоге получишь то что компилятор C++ и так делает, как ты сам сказал когда-то.
А ты бы лучше рассказал, зачем тебе все эти танцы с бубном.
Возможно, что у надзадачи есть изящные решения, не связанные с тем, как обхитрить ООП.
CS>Вот про это CS>
CS>Base t(std::move(b));
CS>Derived* d = new(&b)Derived(std::move(t));
CS>
CS>я думал. Попробуй в members описать std::string поле.
Попробовал, у меня всё заработало.
Скрытый текст
#include <iostream>
#include <string>
#include <memory>
struct A
{
int x;
std::string y;
A(int x, std::string y) : x(x), y(y) {}
virtual const char* who() const { return"A"; }
void show() const { std::cout << (void const*)this << " " << who() << " " << x << " [" << y << "]" << std::endl; }
};
struct B : A
{
virtual const char* who() const { return"B"; }
B(A&& a) : A(std::move(a)) {}
};
int main()
{
A a(123, "mama");
a.show(); // 0xbfbefa58 A 123 [mama]
A t(std::move(a));
a.show(); // 0xbfbefa58 A 123 []
t.show(); // 0xbfbefa64 A 123 [mama]new(&a)B(std::move(t));
a.show(); // 0xbfbefa58 B 123 [mama]
t.show(); // 0xbfbefa64 A 123 []
}
CS>Короче вместо Base(NO_INIT) конструкторов тебе нужно будет писать Base(Base &&moved) конструкторы. Ровно столько же. CS>И это всегда будет требовать temporary при конвертации и ненулевой CPU penalty.
Это, по крайней мере, — в рамках языка. Хоть и UB.
А если добавить перед new(&a) вызов a.~A() — так и вообще станет похоже на использование aligned_storage.
Хакать же все vfptr'ы — непереносимое решение, требующее знания лэяута конкретных классов на конкретной платформе.
Нулевой штраф производительности — это паттерны Стратегия и Состояние.
На NVI там даже лишней косвенности не возникнет, если тебя волнует штраф производительности при дальнейшей работе...
Перекуём баги на фичи!
Re[7]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, c-smile, Вы писали:
J>>Если ты убираешь и конструктор, остается просто возврат указателя — это reinterpret_cast. CS>Ну ок. "Рука бога" вставляет vtbl pointer.
Вот чтобы специально расстроить, напомню: в классе может быть много vfptr'ов.
У первой полиморфной базы — с нулевым смещением; у последующих полиморфных баз; ну и у членов-данных, но они при подмене типа не поменяются.
CS>Для простоты будем считать что кроме VTBL никакой другой практической имплементации виртуальности нам не известно. CS>Во всяком случае для всех компиляторов поддерживающих COM и CORBA объекты из коробки это именно VTBL и ничто другое.
NVI — рукодельщина из коробки.
Если хорошенько шаблонно поколдовать, то можем и автоматизировать её.
Сразу вспоминаются shared_ptr, function и any.
J>>Но если ты хочешь пользоваться встроенной системой типов С++ в соответствии со стандартом — придется соответствовать, не предполагая, в частности, никаких vtbl и прочего. CS>Странно, все говорят про Стандарт, но никто так конкретно и не говорит чем мое решение его нарушает.
Ну как что нарушает. Вагон неопределённого поведения.
Хирургия с подменой vfptr — это частный случай стрельбы по памяти.
placement new — инвалидирует старый объект, ну и что, что почти такой же новый по тому же адресу возник. Как мы видели, компилятор может надеяться на то, что если объект валидный, то и его тип неизменный и известный заранее, и сэкономить на виртуальных вызовах.
CS>Вообще какая-то странная ситуация получается. С одной стороны использование reinterpret_cast конструкций типа как легитимно в C++. CS>А с другой стороны вариация оного так сразу супротив Стандарта.
Стандарт разрешает стрелять в ногу, но говорит, что скорую помощь и патологоанатома будут оплачивать жертва и её родственники.
Перекуём баги на фичи!
Re[8]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, c-smile, Вы писали:
J>>>Если ты убираешь и конструктор, остается просто возврат указателя — это reinterpret_cast. CS>>Ну ок. "Рука бога" вставляет vtbl pointer.
К>Вот чтобы специально расстроить, напомню: в классе может быть много vfptr'ов. К>У первой полиморфной базы — с нулевым смещением; у последующих полиморфных баз; ну и у членов-данных, но они при подмене типа не поменяются.
Нет там полиморфных баз по условию задачи. Еще раз: рассматривается конкретная задача а не конь в ваакуме.
J>>>Но если ты хочешь пользоваться встроенной системой типов С++ в соответствии со стандартом — придется соответствовать, не предполагая, в частности, никаких vtbl и прочего. CS>>Странно, все говорят про Стандарт, но никто так конкретно и не говорит чем мое решение его нарушает.
К>Ну как что нарушает. Вагон неопределённого поведения.
"Имя, сестра, имя!" Что конкретно неопределено?
new(place), использование конструкторов или что?
К>Хирургия с подменой vfptr — это частный случай стрельбы по памяти.
Где я там меняю vfptr?
К>placement new — инвалидирует старый объект, ну и что, что почти такой же новый по тому же адресу возник. Как мы видели, компилятор может надеяться на то, что если объект валидный, то и его тип неизменный и известный заранее, и сэкономить на виртуальных вызовах.
Не может он там экономить. Обращение всегда идет через pointer на базу (Thing).
CS>>Вообще какая-то странная ситуация получается. С одной стороны использование reinterpret_cast конструкций типа как легитимно в C++. CS>>А с другой стороны вариация оного так сразу супротив Стандарта.
К>Стандарт разрешает стрелять в ногу, но говорит, что скорую помощь и патологоанатома будут оплачивать жертва и её родственники.
Николай, давай на технических деталях сфокусируемся, лирику люди поют в политике.
Re[9]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, c-smile, Вы писали:
К>>placement new — инвалидирует старый объект, ну и что, что почти такой же новый по тому же адресу возник. Как мы видели, компилятор может надеяться на то, что если объект валидный, то и его тип неизменный и известный заранее, и сэкономить на виртуальных вызовах.
CS>Не может он там экономить.
ошибаетесь. GCC и Clang успешно справляются с двевертуализацией там, где она не нужна.
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
Re[6]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, Кодт, Вы писали:
CS>>Короче вместо Base(NO_INIT) конструкторов тебе нужно будет писать Base(Base &&moved) конструкторы. Ровно столько же. CS>>И это всегда будет требовать temporary при конвертации и ненулевой CPU penalty.
К>Это, по крайней мере, — в рамках языка. Хоть и UB. К>А если добавить перед new(&a) вызов a.~A() — так и вообще станет похоже на использование aligned_storage.
В чем там UB?
К>Хакать же все vfptr'ы — непереносимое решение, требующее знания лэяута конкретных классов на конкретной платформе.
Да не хакаю я vfptr'ы там нигде! В том то и point. По месту одного объекта создается другой. В чем проблема-то?
К>Нулевой штраф производительности — это паттерны Стратегия и Состояние. К>На NVI там даже лишней косвенности не возникнет, если тебя волнует штраф производительности при дальнейшей работе...
Re[6]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, niXman, Вы писали:
X>Здравствуйте, c-smile, Вы писали:
К>>>placement new — инвалидирует старый объект, ну и что, что почти такой же новый по тому же адресу возник. Как мы видели, компилятор может надеяться на то, что если объект валидный, то и его тип неизменный и известный заранее, и сэкономить на виртуальных вызовах.
CS>>Не может он там экономить.
X>ошибаетесь. GCC и Clang успешно справляются с двевертуализацией там, где она не нужна.
Если обращаться derived.virtualMethod() то да, может.
Но base->virtualMethod() — это совсем другая песня.
Re[11]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, c-smile, Вы писали:
CS>Здравствуйте, niXman, Вы писали:
X>>Здравствуйте, c-smile, Вы писали:
К>>>>placement new — инвалидирует старый объект, ну и что, что почти такой же новый по тому же адресу возник. Как мы видели, компилятор может надеяться на то, что если объект валидный, то и его тип неизменный и известный заранее, и сэкономить на виртуальных вызовах.
CS>>>Не может он там экономить.
почему нет?
X>>ошибаетесь. GCC и Clang успешно справляются с двевертуализацией там, где она не нужна.
CS>Если обращаться derived.virtualMethod() то да, может. CS>Но base->virtualMethod() — это совсем другая песня.
Другая будет если менять base после создания нового объекта
base = turn_A_to<B>(base);
иначе будет UB, компилятор имеет право считать, что vfptr не поменялся и вызывать методы для старого типа.
Re[11]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, c-smile, Вы писали:
CS>Если обращаться derived.virtualMethod() то да, может. CS>Но base->virtualMethod() — это совсем другая песня.
То не подумать ли ещё раз над другой песней?
#include <iostream>
struct A {
virtual void func (void) {std::cout << "A\n";};
};
struct B : A {
virtual void func (void) {std::cout << "B\n";}
};
static int
bar (B *b)
{
b->func(); //this will be inlined in optimized builds.
}
int
main (void)
{
B b;
bar (&b);
return 0;
}
Компилируем gcc 4.8.1 c -O2, смотрим на сгенерированный код
Здравствуйте, Tilir, Вы писали: T>Здравствуйте, c-smile, Вы писали: CS>>Если обращаться derived.virtualMethod() то да, может. CS>>Но base->virtualMethod() — это совсем другая песня. T>То не подумать ли ещё раз над другой песней? T>Компилируем gcc 4.8.1 c -O2, смотрим на сгенерированный код
Это ничего не доказывает. Ну получили мы после оптимизации код, который ведет себя также как неоптимизированный, ну и что? Нужен пример, для которого оптимизация изменит поведение. А в таком тривиальном случае, компилятор заинлайнит виртуальные вызовы даже после "смены типа", причем сделает это правильно:
int
main (void)
{
B b;
bar (&b);
::new (&b) A;
bar (&b);
return 0;
}
в первом случае будет B::f(), а после "смены типа" A::f().
Re[9]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, c-smile, Вы писали:
CS>Нет там полиморфных баз по условию задачи. Еще раз: рассматривается конкретная задача а не конь в ваакуме.
Полиморфная база там есть. (В противовес виртуальной базе и просто базе без виртуальных методов).
Конкретная задача озвучена тобой немножко в вакууме. Понятно, что ты пытаешься гоняться за производительностью, но непонятно, в каком масштабе и вообще зачем.
К>>Ну как что нарушает. Вагон неопределённого поведения.
CS>"Имя, сестра, имя!" Что конкретно неопределено? CS>new(place), использование конструкторов или что?
Я уже сказал: пропатчивание объекта. Ты или стреляешь по памяти, или реконструируешь объект, тем самым инвалидируя предыдущий.
К>>Хирургия с подменой vfptr — это частный случай стрельбы по памяти. CS>Где я там меняю vfptr?
Твои слова или не твои?
Мне нужно решить на самом деле обратную задачу
Вызвать placement new без вызова конструктора.
Для классов с виртуальными функциями new(oldobj) просто меняет (инициализирует)
vtbl. А конструктор инициализирует поля. Мне надо вызвать new(place) но не конструктор.
К>>placement new — инвалидирует старый объект, ну и что, что почти такой же новый по тому же адресу возник. Как мы видели, компилятор может надеяться на то, что если объект валидный, то и его тип неизменный и известный заранее, и сэкономить на виртуальных вызовах.
CS>Не может он там экономить. Обращение всегда идет через pointer на базу (Thing).
Вообще-то, может.
Попробуй скомпилировать вот это на g++ 4.7 с параметрами -O2 и -O0, увидишь разницу.
#include <cstdio>
#include <memory>
struct Base
{
virtual const char* whoami() const { return"Base"; }
};
struct Derived : Base
{
Derived(Base&& b) : Base(b) {}
virtual const char* whoami() const { return"Derived"; }
};
void patch(Base* b)
{
Base t(std::move(*b));
Derived* d = new(b)Derived(std::move(t));
}
int main()
{
Base ob;
Base* pb = &ob;
patch(pb);
printf("%s %s\n", ob.whoami(), pb->whoami()); // -O2: Base Base | -O0: Base Derived
};
MSVC, кстати, даже в самых агрессивных режимах оптимизации форсирует виртуальный вызов от указателя/ссылки, даже если ему не давать повод что-либо заподозрить (закомментировать patch).
К>>Стандарт разрешает стрелять в ногу, но говорит, что скорую помощь и патологоанатома будут оплачивать жертва и её родственники. CS>Николай, давай на технических деталях сфокусируемся, лирику люди поют в политике.
Технические детали — это твоё право делать всё, что угодно well-formed, но некоторые WF программы ведут к undefined behavior, а UB бывает предсказуемым и непредсказуемым, желаемым и нежелаемым.
И кстати, чтобы два раза не вставать.
На всякий случай напоминаю, что
— placement new operator вообще ничего не делает, а new expression вызывает конструктор. Нет такой штуки "вызвать предконструктор, но свалить из тела конструктора". Даже если с помощью исключения мы поймаем момент, когда vfptr уже настроен, а до конструирования членов ещё не дошли, — всё равно, будут проблемы.
— vfptr в ходе конструирования наследника настраивается много раз, по мере прохождения конструкторов баз — в отличие от дотнета, жабы и дельфей.
Перекуём баги на фичи!
Re[7]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, c-smile, Вы писали:
J>>Это делает конструктор. Вернее, стандарт не специфицирует vtbl вообще, но по сути этим занимается конструктор в качестве первого шага, так как указатель на vtbl — это просто скрытый член, который надо проинициализировать.
CS>Это происходит между new и первым конструктором. Но это не суть важно.
То же самое надо сделать и при размещении объекта на стеке, и при инициализации каждой базы в цепочке баз. Нафига компилятору заниматься магией "между", если по сути это просто инициализация скрытого члена? Вот писал бы ты компилятор и тебе понадобилось бы вставить в объект скрытый член — ты бы как поступил? Вставил бы код его инициализации первой строчкой кода конструктора, чтоб потом просто этот конструктор звать в одну инструкцию? Или перед каждым вызовом конструктора впихивал бы код инициализации? С нулевой экономией причем — так как конструктор все равно потом звать надо.
J>>>>Для произвольного левого класса это невозможно сделать, если ты хочешь, чтоб код оставался соответствующим Стандарту. Если классы все под твоим контролем — юзай указатель pimpl, в него ты можешь засунуть все, что угодно (в т.ч. std::string), и не инициализировать, если он уже есть (ну или передавать указатель в конструктор, чтоб уж совсем не зависеть от его точного расположения в классе).
CS>Ищется решение которое вводит наиментшее кол-во сущностей и CPU penalty.
Простое разделение данных и виртуальной иерархии кода, который с этими данными работает — достаточно "наименьшее"?
Тебе ведь по сути это надо — менять обработчик, не трогая данные?
Ну так раздели их полностью.
Вообще, тебя ведь несколько раз попросили уже объяснить свою реальную задачу. Ради чего все эти пляски с подменами?
J>>Но если ты хочешь пользоваться встроенной системой типов С++ в соответствии со стандартом — придется соответствовать, не предполагая, в частности, никаких vtbl и прочего.
CS>Странно, все говорят про Стандарт, но никто так конкретно и не говорит чем мое решение его нарушает.
"твое решение" — это какое? С объединением — я процитировал стандарт. Исходное — ничего не нарушает (разве что ты не должен пользоваться старым указателем, только новым, которые возвращен из turn_thing_to), но кривое и не работает со сколь-нибудь интересными типами (ты и сам про это пишешь).
CS>Вообще какая-то странная ситуация получается. С одной стороны использование reinterpret_cast конструкций типа как легитимно в C++.
Оно очень условно легитимно. Прочитай соответствующий раздел стандарта. По сути вообще нет никаких гарантий со стороны стандарта относительно того, что вернет reinterpret_cast, за исключением очень небольшого количества оговоренных случаев.
CS>А с другой стороны вариация оного так сразу супротив Стандарта.
UB — оно в соответствии со стандартом UB, совсем не супротив
Здравствуйте, Кодт, Вы писали: К>>>placement new — инвалидирует старый объект, ну и что, что почти такой же новый по тому же адресу возник. Как мы видели, компилятор может надеяться на то, что если объект валидный, то и его тип неизменный и известный заранее, и сэкономить на виртуальных вызовах. CS>>Не может он там экономить. Обращение всегда идет через pointer на базу (Thing). К>Вообще-то, может. К>Попробуй скомпилировать вот это на g++ 4.7 с параметрами -O2 и -O0, увидишь разницу.
Скрытый текст
К>
К>#include <cstdio>
К>#include <memory>
К>struct Base
К>{
К> virtual const char* whoami() const { return"Base"; }
К>};
К>struct Derived : Base
К>{
К> Derived(Base&& b) : Base(b) {}
К> virtual const char* whoami() const { return"Derived"; }
К>};
К>void patch(Base* b)
К>{
К> Base t(std::move(*b));
К> Derived* d = new(b)Derived(std::move(t));
К>}
К>int main()
К>{
К> Base ob;
К> Base* pb = &ob;
К> patch(pb);
К> printf("%s %s\n", ob.whoami(), pb->whoami()); // -O2: Base Base | -O0: Base Derived
К>};
К>
К>MSVC, кстати, даже в самых агрессивных режимах оптимизации форсирует виртуальный вызов от указателя/ссылки, даже если ему не давать повод что-либо заподозрить (закомментировать patch).
А не бага-ли это в GCC? Даже если вместо patсh(pb) написать pb = new(pb)Derived; GCC все-равно использует "Base" к качестве результата pb->whoami().
int main()
{
void *pmem = nullptr;
Base *pb = nullptr;
Derived o1;
pmem = &o1;
pb = new(pmem)Base;
printf("%s\n", pb->whoami()); // ok: -O2: Base | -O0: Base
Base o2;
pmem = &o2;
pb = new(pmem)Derived;
printf("%s\n", pb->whoami()); // failed: -O2: Base | -O0: Derived
}
Что интересно, это происходит только если использовать память объекта созданного на стеке.
Base *pb = new Base;
pb = new(pb)Derived;
printf("%s\n", pb->whoami()); // ok: -O2: Derived| -O0: Derived
Re[11]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, k.o., Вы писали:
KO>А не бага-ли это в GCC? Даже если вместо patсh(pb) написать pb = new(pb)Derived; GCC все-равно использует "Base" к качестве результата pb->whoami().
Вообще какая-то муть. На -O2 получаем
int main()
{
Derived o1;
Base* pbb = new(&o1)Base();
Base* pb1 = &o1;
printf("\n");
printf("%s\n", pb1->whoami()); // Base
printf("%s\n", pbb->whoami()); // Base
Base o2;
Derived* pbd = new(&o2)Derived();
Derived* pb2 = (Derived*)&o2;
printf("\n");
printf("%s\n", pb2->whoami()); // Base
printf("%s\n", pbd->whoami()); // Base
Base* o3 = &o1;
Derived* pbm = new(o3)Derived();
Base* pb3 = (Base*)o3;
printf("\n");
printf("%s\n", pb3->whoami()); // Derived
printf("%s\n", pbm->whoami()); // Derived
Base* o4 = &o2;
Derived* pbn = new(o4)Derived();
Base* pb4 = (Base*)o4;
printf("\n");
printf("%s\n", pb4->whoami()); // Base
printf("%s\n", pbn->whoami()); // Base
Base o5[1]; // или любое другое хранилище, например, intptr_t[12345]
Derived* pbz = new(o5)Derived();
Base* pb5 = (Base*)o5;
printf("\n");
printf("%s\n", pb5->whoami()); // Derived
printf("%s\n", pbz->whoami()); // Derived
};
А вот интересно, это баг или неопределённое поведение. Думаю, что всё же второе, потому что мы конструируем объект поверх существующего, лежащего в автоматическом или статическом хранилище (для последнего — нужно o1-o5 вынести из функции или снабдить static'ами). Безотносительно того, будем ли предварительно инвалидировать объекты, вызывая у них деструкторы.
Ну не предназначены именованные объекты для того, чтобы над ними творили такую жестокость.
Перекуём баги на фичи!
Re[12]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, Кодт, Вы писали: К>Здравствуйте, k.o., Вы писали: KO>>А не бага-ли это в GCC? Даже если вместо patсh(pb) написать pb = new(pb)Derived; GCC все-равно использует "Base" к качестве результата pb->whoami(). К>Вообще какая-то муть. На -O2 получаем
К>А вот интересно, это баг или неопределённое поведение. Думаю, что всё же второе, потому что мы конструируем объект поверх существующего, лежащего в автоматическом или статическом хранилище (для последнего — нужно o1-o5 вынести из функции или снабдить static'ами). Безотносительно того, будем ли предварительно инвалидировать объекты, вызывая у них деструкторы.
В стандарте я на это запрета не видел, при этом там подробно описывается в каких случаях такое использование storage автоматических объектов приведет к UB, соответственно в прочих случаях все должно работать. К>Ну не предназначены именованные объекты для того, чтобы над ними творили такую жестокость.
А как же, например, какой-нибудь там, aligned_storage?
Re[13]: С++, как вызвать конструктор объекта по месту?
Здравствуйте, k.o., Вы писали:
К>>А вот интересно, это баг или неопределённое поведение. Думаю, что всё же второе, потому что мы конструируем объект поверх существующего, лежащего в автоматическом или статическом хранилище (для последнего — нужно o1-o5 вынести из функции или снабдить static'ами). Безотносительно того, будем ли предварительно инвалидировать объекты, вызывая у них деструкторы.
KO>В стандарте я на это запрета не видел, при этом там подробно описывается в каких случаях такое использование storage автоматических объектов приведет к UB, соответственно в прочих случаях все должно работать.
Возможно, что это ещё и дефект стандарта.
Ну вот не привиделось комитетчикам в страшном сне такое надругательство.
К>>Ну не предназначены именованные объекты для того, чтобы над ними творили такую жестокость.
KO>А как же, например, какой-нибудь там, aligned_storage?
aligned_storage — это хорошо выравненный POD. Его вообще можно memset'ить как угодно, — почему бы не использовать и для placement new.