Re[7]: placement new
От: sergii.p  
Дата: 11.12.22 09:39
Оценка: +1
Здравствуйте, maks1180, Вы писали:

M>Адрес же cl1 и cc будет отличаться.


ну а так?

std::variant<ClientCommon, Client1, Client2> v;
v = ClientCommon{};
v = Client1{std::move(std::get<ClientCommon>(v))};
Re[8]: placement new
От: maks1180  
Дата: 11.12.22 11:29
Оценка:
SP>
SP>std::variant<ClientCommon, Client1, Client2> v;
SP>v = ClientCommon{};
SP>v = Client1{std::move(std::get<ClientCommon>(v))};
SP>


Идея хорошая, только я без std::move хотел обойтись. Если Client1 наследник от ClientCommon, то не нужно дедать std::move, так как он по тому же адресу должен лежать.
Или не так ?
===============================================
(реклама, удалена модератором)
Re[2]: placement new
От: maks1180  
Дата: 11.12.22 11:35
Оценка:
Спасибо, но я хотел бы обойтись без std::move, тем более без двойного.
Ведь мы же создаём объект на том же месте, или конструктор может затереть всё нулями ?
===============================================
(реклама, удалена модератором)
Re[3]: placement new
От: vopl Россия  
Дата: 11.12.22 12:45
Оценка: +1
Здравствуйте, maks1180, Вы писали:

M>Спасибо, но я хотел бы обойтись без std::move, тем более без двойного.

M>Ведь мы же создаём объект на том же месте, или конструктор может затереть всё нулями ?

Конструктор не затрет, если он будет тривиальным и нигде не будет инициировано zero-initialization, во всех остальных случаях — затрет. Но это семечки, есть более страшная штука, касается UB по причине использования несконструированных (вне lifetime) значений, тех самых, которые не были "затерты" конструктором и остальсь от предыдущего объекта. Это практически опасная ситуация, потому что компилятор будет чудить по причине этого UB.

Другими словами — не делай так.
Re[3]: placement new
От: andyp  
Дата: 11.12.22 14:23
Оценка:
Здравствуйте, maks1180, Вы писали:

M>Да. Но нужно как-то поменять v-table у объекта и он станет объектом другого класса ?


Так нельзя. Нарушаешь стандарт на счёт времени жизни. Обязательно нужно конструктор и деструктор звать. Так что, placement new как в variant — единственный правильный путь имхо.
Re[3]: placement new
От: Sm0ke Россия ksi
Дата: 11.12.22 17:24
Оценка:
Здравствуйте, 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_base может отличаться от &m_data
Re[9]: placement new
От: Sm0ke Россия ksi
Дата: 11.12.22 17:50
Оценка:
Здравствуйте, maks1180, Вы писали:

SP>>
SP>>std::variant<ClientCommon, Client1, Client2> v;
SP>>v = ClientCommon{};
SP>>v = Client1{std::move(std::get<ClientCommon>(v))};
SP>>


M>Идея хорошая, только я без std::move хотел обойтись. Если Client1 наследник от ClientCommon, то не нужно дедать std::move, так как он по тому же адресу должен лежать.

M>Или не так ?

1. Нет гарантий, что это так
2. Нет гарантий, что данные не будут перезатёрты

//
Можно хранить параметры отдельно, и добавить указатель на них в ClientCommon, если не хочешь их мувать.

//
Я понимаю, что ты хочешь досоздать Client1 из ClientCommon, а cpp этого нет.
Но тогда можно сделать pimpl.

struct ClientCommon;

struct ClientImpl { ClientCommon * m_outer; };
struct Client1 : ClientImpl {};
struct Client2 : ClientImpl {};

struct ClientCommon {
  // общие данные
  
  // реализация
  keep<ClientImpl, Client1, Client2> m_impl;
};
Отредактировано 11.12.2022 17:51 Sm0ke . Предыдущая версия .
Re[4]: placement new
От: vopl Россия  
Дата: 11.12.22 18:11
Оценка:
Здравствуйте, vopl, Вы писали:

V>Здравствуйте, maks1180, Вы писали:


M>>Спасибо, но я хотел бы обойтись без std::move, тем более без двойного.

M>>Ведь мы же создаём объект на том же месте, или конструктор может затереть всё нулями ?

V>Конструктор не затрет, если он будет тривиальным и нигде не будет инициировано zero-initialization, во всех остальных случаях — затрет. Но это семечки, есть более страшная штука, касается UB по причине использования несконструированных (вне lifetime) значений, тех самых, которые не были "затерты" конструктором и остальсь от предыдущего объекта. Это практически опасная ситуация, потому что компилятор будет чудить по причине этого UB.


V>Другими словами — не делай так.


Кстати кстати, есть еще вот такая штука https://en.cppreference.com/w/cpp/utility/launder, судя по всему это то что тебе нужно, с ее помощью можно заблокировать упомянутое UB
Re[3]: placement new
От: rg45 СССР  
Дата: 11.12.22 21:38
Оценка: 27 (2)
Здравствуйте, maks1180, Вы писали:

R>>Согласно стандарту языка, использование одной и той же области памяти для размещения двух разных объектов порождает неопределенное поведение. Нельзя так делать.


M>Даже если первый объект больше не будет использован после создания второго ?


Ты знаешь, наверное, я был не совсем прав, все-таки, на счет неопределенного поведения (смайлик от Сигмы заставил открыть стандарт). И оказалось, не все так однозначно, как мне казалось. В частности, в стандарте прямо говорится, что программа может завершать время жизни без вызова деструктора и, само по себе это не влечет неопределенного поведения:

https://timsong-cpp.github.io/cppwp/basic.life#5

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 в чистом виде, но программирование на грани фола, что называется. Без особой необходимости пускаться в такие авантюры лично я бы не стал.
--
Не можешь достичь желаемого — пожелай достигнутого.
Отредактировано 11.12.2022 21:41 rg45 . Предыдущая версия .
Re[10]: placement new
От: sergii.p  
Дата: 12.12.22 08:50
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>2. Нет гарантий, что данные не будут перезатёрты


ага
https://godbolt.org/z/e5M49nc7P
но с вариантами всё будет работать. Там создаётся новый вариант и только потом вызывается конструктор перемещения. В общем, два перемещения. Если вызывать emplace то всё будет печально.
Re[4]: placement new
От: σ  
Дата: 12.12.22 10:20
Оценка: 9 (2)
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.


https://cplusplus.github.io/CWG/issues/2523.html
Re[5]: placement new
От: rg45 СССР  
Дата: 12.12.22 14:40
Оценка: :)
Здравствуйте, σ, Вы писали:

σ>https://cplusplus.github.io/CWG/issues/2523.html


--
Не можешь достичь желаемого — пожелай достигнутого.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.