170 похожих чатов

Всем привет. В одном сегменте кода мне необходимо выполнять ручное

размещение/удаление массива элементов не тривиального типа на вручную выделенной памяти. Тк в проекте поддерживается cpp17 по итогу остановился на std::uninitialized_default_construct_n + std::destroy_n. Создание элементов можно заменить на placement new для массива - конструкторы отрабатывают корректно, но вот что делает и как работает placement delete я не разобрался. Кто-то работал с 'non-allocating placement deallocation functions' или это нечто ненужное и до C++17 необходимо использовать цикл + ручной вызов деструктора по указателю ~T()?

https://en.cppreference.com/w/cpp/memory/new/operator_delete

Вот тут можно посмотреть и запустить код
https://coliru.stacked-crooked.com/view?id=0885bd40bb355840
https://godbolt.org/z/1z6537Kve

12 ответов

19 просмотров

Судя по примечаниям (13)(14) на cppref это не нужно руками звать никогда.

всякие std::destroy_n это сахар в 17++, вот и все. они делают тоже самое, просто сами, ты как бы экономишь время вот и все. если деструктор нужен, да ты его должен вызвать. всякие алигн стораджы и юнионы, используют по большей части во всяких эмбедетах, когда память всегда четко распределена, но возможно не известно под какие драйвера(девайсы) тебе как бы из внешки прилетит инфа. мол 10 датчиков дыма 15 пожарных. ты делаешь placement new.

0) я не писал продакшн код ни с одной из этих фич С++ и его стандартной библиотеки, но провел прилично времени за главами стандарта про объектную модель 1) вызов недеаллоцирующего operator delete[]() (не путать с delete expression) ничего не делает и никакую семантику в себе не несет. то есть вы можете его вызвать, и вам ничего за это не будет, но он не закончит время жизни объектов, созданных new, как вы можете от него ожидать 2) смысл существования этой перегрузки operator delete[]() изложен в стандарте. от себя могу добавить предположение, что и симметрии ради с неаллоцирующим operator new[]() 3) механизм работы placement delete постигнуть невозможно, так как такого выражения не существует — delete expression не предоставляет возможность передавать дополнительные аргументы в функцию деаллокации, в отличие от new 4) создавая объекты A через placement array new, вы не переиспользуете отдельные aligned_storage под хранение объектов A, а переиспользуете сам массив aligned_storag'ей 5.1) разница в том, что в этом случае вы не можете использовать арифметику указателей на основе place для того, чтобы получать указатели на объекты A, потому что массива place больше нет. для этого годится только указатель, который вернет new[] (и который вы игнорируете), либо отмытый (std::launder) ptr или любой другой указатель на начало place. 5.2) а еще это выстрелит, если вы усилите требования к выравниванию aligned_storage (например, чтобы выравнивать по 64-байтовым кэш-линиям), потому что нет возможности передать выравнивание в placement new[] 6) ваше С++17 решение совершенно верное, и если вам нужно портировать его туда, где эти алгоритмы недоступны, то проще и надежнее всего написать руками то же, что они делают под капотом, а именно вызывают placement new для каждого aligned_storage и так же по одному вызывают деструкторы A потом 7) возможно, вы уже знаете или поняли к этому моменту, что даже после успешного вызова std::uninitialized_default_construct_n вы не можете считать place массивом объектов А и заниматься арифметикой указателей на основе этого предположения — он остается массивом aligned_storage 8) у меня нет внятного ответа, почему в этом случае delete[] творит такую дичь. в стандарте я вижу лишь, что он должен работать. видимо, как обычно плохо смотрю возможно, @ddvamp может что-то добавить

Евгений-Пройдаков Автор вопроса
Vlad
0) я не писал продакшн код ни с одной из этих фич ...

Влад, спасибо за развёрнутый комментарий. По пункту 7 я понимаю, что если выравнивание будет отличаться, то все взлетит на воздух и нужно отдельно использовать каждую ячейку стороджа.

Евгений Пройдаков
Влад, спасибо за развёрнутый комментарий. По пункт...

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

Евгений-Пройдаков Автор вопроса
Vlad
правда, это UB даже при совпадающем выравнивании. ...

typename std::aligned_storage<1024 * sizeof(T), alignof(T)>::type data; так было-бы лучше? Реальный код использует результат std::allocator или custom где память уже выровнена по странице да и объекты сами по размеру кеш линии.

Евгений Пройдаков
typename std::aligned_storage<1024 * sizeof(T), al...

чтобы потом сделать new (data) T[1024]? может, и прокатило бы, если бы вы писали под 20 стандарт и были довольны стандартным operator new[](std​::​size_­t, void*). если эти условия не соблюдаются, то вы упираетесь в стену имя которой array allocation overhead лучше всего взять С++17 решение, и если нужно обращаться по индексу, то написать простейшую обертку над reinterpret_cast'ом (godbolt). всевозможные проверки оставил за скобками

Vlad
0) я не писал продакшн код ни с одной из этих фич ...

По поводу п.8: в примере для delete expression не работает отбрасывание вызова deallocation function http://eel.is/c++draft/expr.delete#7.3, т.к. allocation function является omitted только для constant expression http://eel.is/c++draft/expr.new#13 Как следствие получаем UB из-за нарушения предусловия deallocation function http://eel.is/c++draft/new.delete.array#9

Alexander Tulikov
По поводу п.8: в примере для delete expression не ...

я согласен, что оно так получается в итоге, но мне не понятно, зачем она вызывается (и зачем ее считать вызванной) для new, которому не нужно выделять память http://eel.is/c++draft/expr.new#10

Vlad
я согласен, что оно так получается в итоге, но мне...

Как вариант потому, что пользователь может её заменить на аналог с дополнительным функционалом (зануление памяти то же). А в прикладном смысле не понятно, откуда брать информацию о том, размещающий был вызов new или аллоцирующий.

Alexander Tulikov
Как вариант потому, что пользователь может её заме...

вариант с заменой звучит интересно, но представляется проблематичным в реализации ввиду этого пункта

Vlad
вариант с заменой звучит интересно, но представляе...

Это относится только к глобальным функциям, на уровне класса их заменять можно.

Похожие вопросы

Обсуждают сегодня

Добрый вечер. Есть вопрос, а может и предложение. Был у меня диалог в другой группе о делфи и я задался вопросом: "А нельзя ли в делфи цвет //коментария и {комментария} сде...
Kraszx
24
Мдя, прикол, боевая сборка запускается (именно под отладчиком) после F9 примерно полторы минуты (97 секунд если быть точным). Начал копать - проблема детектится сразу - зависа...
Александр (Rouse_) Багель
38
Всем привет! Подскажи, пожалуйста, как передать в TComboBox сразу значение и id записи. На Delphi я делал так: ComboBox1.Items.AddObject('Какое-то значение', Pointer(id запис...
Евгений
13
я так понимаю, я так подозреваю, что создание такого плагина для человека, кто умеет писать плагины для делфи потребует минут 5-10 времени. но это мое подозрение. хотелось бы ...
Kraszx
7
Товарищи, кто работа с iphelper? Или может я в самой логике ошибки фигачу, не пойму.... var ifTable : PMIB_IFTABLE; size, corSize: DWORD; Buffer ...
Warfarellen
4
Здравствуйте, вопрос по структурам данных. Были у вас случаи, когда пришлось писать деревья или двунаправленные списки?
/ /
50
Коллеги, добрый вечер. Создаю коллекцию от TFPGMap, ключ - перечисление, значение - целое. Нужно отсортировать коллекцию по значению. Как это можно сделать?
Kirill Filippenok
11
Привет, такой вопросик появился кажется ли вам что Rust слишком сложный/строгий для высокоуровневого программирования и слишком "безопасный"/строгий для низкоуровневого?
Крокант
10
Скажи а ты когда этот канал создавал ты уже дельфи не любил, или это со временем пришло?
Роман Лях (rgreat)
18
Всем привет! Использую кастомное модальное диалоговое окошко, все по классике - mrOK, mrCancel как ModalResult. Однако есть нюанс - в главной форме есть универсальный обработч...
Олег Гранишевский
20
Карта сайта