Информация об изменениях

Сообщение Re[4]: ::operator new() в самописном стэке от 10.06.2023 18:53

Изменено 10.06.2023 18:55 Sm0ke

Re[4]: ::operator new() в самописном стэке
Здравствуйте, rg45, Вы писали:

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


S>>
S>>return reinterpret_cast<pointer>(
S>>  ::operator new(s_size * p_reserve, s_align, std::nothrow)
S>>);
S>>


R>Вообще, этот фрагмент настораживает. Здесь ты выполняешь преобразование указаетля на просто кусок памяти к указателю на объект, что небезопасно в общем случае. Если Т — это нетривиально конструируемый тип, то время жизни объекта в этой точке еще не началось и любая попытка обращения к этому объекту порождает неопределенное поведение. Использовать данный кусок памяти как объект типа Т можно будет только после выполнения placement new. Но в таком случае и никаких преобразований не понадобится, ибо placement new сразу возвратит указатель нужного типа.


placement new будет в методе emplace_back(). А при m_count == 0 не должно быть обращений к непроинициализированной памяти.

Конструктор лишь резервирует память под массив. Создание объектов там будет по требованию.

Исходник этого вектора на гитхабе (в процессе написания):
https://github.com/deemetrius/ksi/blob/main/ksi/src_just/just.vector.ixx

Вот вопрос: как лучше написать метод insert(), emplace() чтобы было exception safety? Если конструктор элемента кинет исключение.

Вариант 1: Раздвигать последующие элементы, placement new, ловить исключение (сдвигать обратно и рефровать), обновлять count когда нет исключения.
Вариант 2: В отдельном месте placement new, потом memcpy в раздвинутое место массива.
Вариант 3: ...
Re[4]: ::operator new() в самописном стэке
Здравствуйте, rg45, Вы писали:

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


S>>
S>>return reinterpret_cast<pointer>(
S>>  ::operator new(s_size * p_reserve, s_align, std::nothrow)
S>>);
S>>


R>Вообще, этот фрагмент настораживает. Здесь ты выполняешь преобразование указаетля на просто кусок памяти к указателю на объект, что небезопасно в общем случае. Если Т — это нетривиально конструируемый тип, то время жизни объекта в этой точке еще не началось и любая попытка обращения к этому объекту порождает неопределенное поведение. Использовать данный кусок памяти как объект типа Т можно будет только после выполнения placement new. Но в таком случае и никаких преобразований не понадобится, ибо placement new сразу возвратит указатель нужного типа.


placement new будет в методе emplace_back(). А при m_count == 0 не должно быть обращений к непроинициализированной памяти.

Конструктор лишь резервирует память под массив. Создание объектов там будет по требованию.

Исходник этого вектора на гитхабе (в процессе написания):
https://github.com/deemetrius/ksi/blob/main/ksi/src_just/just.vector.ixx

Вот вопрос: как лучше написать метод insert(), emplace() чтобы было exception safety? Если конструктор элемента кинет исключение.

Вариант 1: Раздвигать последующие элементы, placement new, ловить исключение (сдвигать обратно и рефровать), обновлять count когда нет исключения.
Вариант 2: В отдельном месте placement new, потом memcpy в раздвинутое место массива.
Вариант 3: ...

В варианте 1 возможно изменение capacity даже при исключении. В варианте 2 при исключении capacity прежнее.