Предполагаю, что ваша память достаточно выровнена для вашего T
. Вероятно, вы хотите это проверить.
Следующая проблема есть исключения. Мы действительно должны написать две версии, одна из которых может заключаться в том, что построение вызовет исключение, а одно без него.
Я напишу исключительную безопасную версию.
template<class T, class...Args>
T* construct_n_exception_safe(std::size_t n, void* here, Args&&...args) {
auto ptr = [here](std::size_t i)->void*{
return static_cast<T*>(here)+i;
};
for(std::size_t i = 0; i < n; ++i) {
try {
new(ptr(i)) T(args...);
} catch(...) {
try {
for (auto j = i; j > 0; --j) {
ptr(j-1)->~T();
}
} catch (...) {
exit(-1);
}
throw;
}
}
return static_cast<T*>(here);
}
и не исключение безопасный вариант:
template<class T, class...Args>
T* construct_n_not_exception_safe(std::size_t n, void* here, Args&&...args) {
auto ptr = [here](std::size_t i)->void*{
return static_cast<T*>(here)+i;
};
for(std::size_t i = 0; i < n; ++i) {
new (ptr(i)) T(args...);
}
return static_cast<T*>(here);
}
Вы можете сделать систему, основанную тегов доставки, чтобы выбрать между ними в зависимости от того, если строительство T
от Args&...
бросков или нет. Если оно выбрасывается, а ->~T()
нетривиально, используйте безопасный для исключения.
C++ 17 предоставляет некоторые новые функции для выполнения именно этих задач. Они, вероятно, справляются с угловыми делами, которые у меня нет.
Если вы пытаетесь подражать new[]
и delete[]
, если T
имеет нетривиальное dtor вам придется вставлять сколько T
вы создали в блоке.
Типичный способ сделать это - попросить дополнительную комнату для счета на спереди блока. Т.е., запросите sizeof(T)*N+K
, где K
может быть sizeof(std::size_t)
.
Теперь в вашем new[]
эмуляторе, N
в первый бит, а затем позвоните construct_n
на блок сразу после него.
В delete[]
вычтите из переданного в указателе sizeof(std::size_t)
, прочитайте N
, а затем уничтожьте объекты (справа налево до заказа на строительство зеркала).
Все это потребует тщательной оценки try
- catch
.
Если, однако, ~T()
тривиальна, как ваш эмулировать new[]
и delete[]
не храним, что дополнительные std::size_t
и они не читали его.
(Обратите внимание, что это как подражатьnew[]
и delete[]
. Как именно new[]
и delete[]
работа зависит от реализации. Я просто набрасывать один способ, которым Вы можете эмулировать их, не могут быть совместимы с тем, как они работают в вашей системе. Например, некоторые АБИСЫ всегда могут хранить N
даже если ->~T()
тривиален, или множество других вариаций.)
Как отмечают О.П., вы также можете проверить тривиальное строительство до беспокоясь об этом.
Существует версия размещения новых для массивов ... но могут быть проблемы с выравниванием. Это [это] (http://coliru.stacked-crooked.com/a/01699890c4ae1ac0), что вам нужно? – AndyG
@AndyG: Вероятно, нет, потому что для размещения 'new []' используется некоторое пространство для записи информации, используемой 'delete []'. – einpoklum