Założę się, że twoja pamięć jest wystarczająco wyrównana dla twojego T
. Prawdopodobnie chcesz to sprawdzić.
Następnym problemem są wyjątki. Naprawdę powinniśmy napisać dwie wersje, jedną z możliwością, że konstruowanie spowoduje wyjątek, a jeden bez.
Napiszę bezpieczną wersję wyjątku.
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);
}
a nie wyjątek bezpieczna wersja:
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);
}
Można zrobić system oparty tag-wysyłka wybierać między nimi w zależności czy konstruowania T
z Args&...
rzuca czy nie. Jeśli rzuca, a ->~T()
nie jest trywialne, użyj wyjątku bezpiecznego.
C++ 17 udostępnia kilka nowych funkcji do wykonania dokładnie tych zadań. Prawdopodobnie zajmują się narożnymi kopalniami, a nie kopią.
Jeśli próbujesz naśladować new[]
i delete[]
, jeśli T
ma nietrywialne dtor będziesz musiał umieścić ile T
utworzony w bloku.
Typowym sposobem, aby to zrobić, jest poprosić o dodatkowy pokój dla licznika przy z przodu bloku. Tj., Pytaj o sizeof(T)*N+K
, gdzie K
może być sizeof(std::size_t)
.
Teraz w emulatorze new[]
, rzeczy N
do pierwszego bitu, a następnie zadzwoń construct_n
na bloku zaraz po nim.
W delete[]
odejmij sizeof(std::size_t)
od wskazanego kursora, przeczytaj N
, a następnie zniszcz obiekty (od prawej do lewej, aby odzwierciedlić kolejność konstrukcji).
Wszystko to będzie wymagało zachowania ostrożności try
- catch
.
Jeśli jednak ~T()
jest trywialne, zarówno swoje emulowane new[]
i delete[]
nie przechowywać ten dodatkowy std::size_t
ani nie czytać.
(Zauważ, że jest to jak naśladowaćnew[]
i delete[]
. Jak dokładnie new[]
i delete[]
praca jest zależna od implementacji. Ja tylko szkicowanie na jeden sposób można je naśladować, to może nie być zgodne z tym, jak one działają w systemie. na przykład, niektóre Abis może zawsze przechowywać N
nawet jeśli ->~T()
jest trywialna lub mnóstwo innych wariantów.)
Jak zauważył OP, można również sprawdzić za trywialny budowy przed kłopotać się powyższym.
Istnieje nowa wersja miejsca docelowego dla tablic ... ale mogą występować problemy z wyrównaniem. Czy [to] (http://coliru.stacked-crooked.com/a/01699890c4ae1ac0) to, czego potrzebujesz? – AndyG
@AndyG: Prawdopodobnie nie, ponieważ umieszczenie 'new []' używa spacji do zapisania informacji, które będą używane przez 'delete []'. – einpoklum