ein*_*ica 6 c++ memory-management placement-new c++11
我正在使用自定义分配和删除工作一些内存空间,这是使用我无法控制的类似malloc的接口(即分配n个字节或释放已分配的ptr).所以,没什么delete[].
现在,我想构建一个T的数组.我得到了空间auto space_ptr = magic_malloc(n*sizeof(T)).现在我想做一些像array-placement-new这样的内容来构建n个元素.我该怎么办?...或者我应该从1循环到n并构造单个T?
注意:
alignof(T)分歧sizeof(T)).如果你想解决对齐问题,那就更好了,但为了简单起见你可能会忽略它.我会假设你的记忆与你的记忆充分对齐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);
}
Run Code Online (Sandbox Code Playgroud)
和非例外的安全版本:
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);
}
Run Code Online (Sandbox Code Playgroud)
你可以做一个基于标签调度的系统来根据是否T从Args&...投掷构造来选择它们.如果它抛出并且->~T()非常重要,请使用异常安全的.
C++ 17公开了一些新功能来完成这些任务.他们可能处理我不喜欢的角落案件.
如果你试图效仿new[]和delete[],如果T有一个不平凡的析构函数,你必须嵌入多少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[]工作依赖于实现.我只是勾勒出一种可以模拟它们的方式,它可能与它们在您的系统上的工作方式不兼容.例如,某些ABI可能总是存储,N即使->~T()是微不足道的,或无数的其他变化.)
正如OP所指出的那样,您可能还需要在烦恼之前检查一些简单的构造.