귀하의 메모리가 귀하의 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);
}
당신은 Args&...
에서 T
을 구성하는 발생 여부를 경우에 따라 그들 사이에 선택할 수있는 태그 파견 기반 시스템을 할 수 있습니다. 던지면 ->~T()
이 중요하지 않으므로 예외적 인 것을 사용하십시오.
C++ 17에서는 이러한 작업을 정확하게 수행하는 몇 가지 새로운 기능을 제공합니다. 그들은 아마도 내가하지 않은 코너 케이스를 처리 할 것입니다.
당신은 T
당신이 블록에서 만든 방법 T
많은 포함해야합니다 적지 않은 dtor이있는 경우, new[]
및 delete[]
을 모방하려는 경우.
일반적인 방법은 블록의 앞면에서 여분의 공간을 요청하는 것입니다. 즉, sizeof(T)*N+K
을 요청하십시오. 여기서 K
은 sizeof(std::size_t)
일 수 있습니다.
에뮬레이터에서 을 첫 번째 비트에 넣은 다음 바로 뒤에 construct_n
을 호출하십시오. delete[]
에서
, 포인터 전달에서 sizeof(std::size_t)
빼기, N
을 읽은 다음 개체를 파괴 (에서 오른쪽에서 왼쪽으로 시공 순서를 미러링).
이 모든 사항은주의해야합니다. try
- catch
.
~T()
이 약간이라면 에뮬레이트 된 new[]
과 은 모두 여분의 문자를 저장하지 않으며 읽지도 않습니다.
(이
new[]
및
delete[]
. 정확히 어떻게
new[]
을 에뮬레이션하는 방법이며,
delete[]
작업을 구현 의존합니다. 난 그냥 당신이 그들을 모방 수있는 하나의 방법을 스케치하고있어, 그들이 작동하는 방법과 호환되지 않을 수 있습니다 시스템에. 예를 들어, 일부 ABI를 항상 경우에도
->~T()
사소한, 또는 다른 변화의 무수한
N
을 저장할 수 있습니다.)
을 영업 이익으로 언급 한 바와 같이, 당신은 또한 사소한 건설을 확인 할 수 있습니다 이전에 위와 함께 성가시다.
배열에 새로운 배치 버전이 있지만 정렬 문제가있을 수 있습니다. [this] (http://coliru.stacked-crooked.com/a/01699890c4ae1ac0)가 필요합니까? – AndyG
@AndyG : 배치'new []'는'delete []'에서 사용할 정보를 쓸 공간을 사용하기 때문에 아마 그렇지 않을 것입니다. – einpoklum