Идея хорошая, только я без std::move хотел обойтись. Если Client1 наследник от ClientCommon, то не нужно дедать std::move, так как он по тому же адресу должен лежать.
Или не так ?
Спасибо, но я хотел бы обойтись без std::move, тем более без двойного.
Ведь мы же создаём объект на том же месте, или конструктор может затереть всё нулями ?
Здравствуйте, maks1180, Вы писали:
M>Спасибо, но я хотел бы обойтись без std::move, тем более без двойного. M>Ведь мы же создаём объект на том же месте, или конструктор может затереть всё нулями ?
Конструктор не затрет, если он будет тривиальным и нигде не будет инициировано zero-initialization, во всех остальных случаях — затрет. Но это семечки, есть более страшная штука, касается UB по причине использования несконструированных (вне lifetime) значений, тех самых, которые не были "затерты" конструктором и остальсь от предыдущего объекта. Это практически опасная ситуация, потому что компилятор будет чудить по причине этого UB.
Здравствуйте, maks1180, Вы писали:
M>Да. Но нужно как-то поменять v-table у объекта и он станет объектом другого класса ?
Так нельзя. Нарушаешь стандарт на счёт времени жизни. Обязательно нужно конструктор и деструктор звать. Так что, placement new как в variant — единственный правильный путь имхо.
Здравствуйте, maks1180, Вы писали:
S>> T * ret = new (&m_data) T(std::forward<T_args>(p_args) ...);
M>Разве ret может отличатся от &m_data ?
Вроде нет. Значит можно написать return &m_data; а ret убрать.
M>Как показывает мой опыт, добавление промежуточного указателя m_base, может повлечь снижение производительности за счёт промаха кэша.
M>Идея хорошая, только я без std::move хотел обойтись. Если Client1 наследник от ClientCommon, то не нужно дедать std::move, так как он по тому же адресу должен лежать. M>Или не так ?
1. Нет гарантий, что это так
2. Нет гарантий, что данные не будут перезатёрты
//
Можно хранить параметры отдельно, и добавить указатель на них в ClientCommon, если не хочешь их мувать.
//
Я понимаю, что ты хочешь досоздать Client1 из ClientCommon, а cpp этого нет.
Но тогда можно сделать pimpl.
Здравствуйте, vopl, Вы писали:
V>Здравствуйте, maks1180, Вы писали:
M>>Спасибо, но я хотел бы обойтись без std::move, тем более без двойного. M>>Ведь мы же создаём объект на том же месте, или конструктор может затереть всё нулями ?
V>Конструктор не затрет, если он будет тривиальным и нигде не будет инициировано zero-initialization, во всех остальных случаях — затрет. Но это семечки, есть более страшная штука, касается UB по причине использования несконструированных (вне lifetime) значений, тех самых, которые не были "затерты" конструктором и остальсь от предыдущего объекта. Это практически опасная ситуация, потому что компилятор будет чудить по причине этого UB.
V>Другими словами — не делай так.
Здравствуйте, maks1180, Вы писали:
R>>Согласно стандарту языка, использование одной и той же области памяти для размещения двух разных объектов порождает неопределенное поведение. Нельзя так делать.
M>Даже если первый объект больше не будет использован после создания второго ?
Ты знаешь, наверное, я был не совсем прав, все-таки, на счет неопределенного поведения (смайлик от Сигмы заставил открыть стандарт). И оказалось, не все так однозначно, как мне казалось. В частности, в стандарте прямо говорится, что программа может завершать время жизни без вызова деструктора и, само по себе это не влечет неопределенного поведения:
A program may end the lifetime of an object of class type without invoking the destructor, by reusing or releasing the storage as described above.
Но надо понимать, что деструктор объекта при этом не вызывается, а вот это уже может порождать неопределенное поведение. В этом же пунтке сказано вот что:
In this case, the destructor is not implicitly invoked and any program that depends on the side effects produced by the destructor has undefined behavior.
То есть, не UB в чистом виде, но программирование на грани фола, что называется. Без особой необходимости пускаться в такие авантюры лично я бы не стал.
--
Не можешь достичь желаемого — пожелай достигнутого.
Здравствуйте, Sm0ke, Вы писали:
S>2. Нет гарантий, что данные не будут перезатёрты
ага https://godbolt.org/z/e5M49nc7P
но с вариантами всё будет работать. Там создаётся новый вариант и только потом вызывается конструктор перемещения. В общем, два перемещения. Если вызывать emplace то всё будет печально.
R>Но надо понимать, что деструктор объекта при этом не вызывается, а вот это уже может порождать неопределенное поведение. В этом же пунтке сказано вот что:
R>
R>In this case, the destructor is not implicitly invoked and any program that depends on the side effects produced by the destructor has undefined behavior.