假设我有:
标识符 | 意义 |
---|---|
|
非默认可构造类 |
|
函数返回
|
|
正 值 |
现在,我想使用
n
在堆上连续生成 T
gen
对象 - 但这样我以后就可以销毁所有它们并在第一个地址上使用 delete[]
释放内存其中。
如果
T
是默认可构造的,那么这很简单:
T* my_t_objects = new[T](n);
之后我可以
delete[] my_t_objects
,鲍勃是我的叔叔。但是 - 当我无法默认构造时, array-new 将不起作用。有没有其他方法可以达到同样的效果...
gen
不带参数时,即 T gen()
?gen
采用索引时,即T gen(size_t)
(在这种情况下我无法对所有元素进行相同的调用)?我的直观想法是为
n
对象分配内存,然后随着索引的增加调用placement-new
n
次;但如果我这样做,我有点怀疑从分配中获得的 delete[]
指针上的 T *
是否真的能做必要的事情。
备注:
std::vector<T>
和 std::generate
,谢谢 :-)gen()
可以假设为noexcept
。T
的演员都不是公开的,并且 gen
是朋友。如果您不介意实例化大量函数,您可以将运行时值
size
转换为常量表达式,然后照常转换 new[]{...}
。这将产生运行时成本,因为它需要多次检查条件才能找到函数模板的正确实例化 - 因此,在速度很重要的情况下,这不是有用的。
此示例支持最大尺寸为 256 的数组,但它很容易扩展:
template <class T, class G, std::size_t N = 0>
T* new_plus(std::size_t size, G&& gen) {
if constexpr (N > 256) { // adjust the maximum amount as needed
std::cerr << "too large array requested " << size << '\n';
std::terminate();
} else { // fill with extra shortcuts if the maximum amount is increased
if (size > N + 128) return new_plus<T, G, N + 129>(size, std::forward<G>(gen));
if (size > N + 64) return new_plus<T, G, N + 65>(size, std::forward<G>(gen));
if (size > N + 32) return new_plus<T, G, N + 33>(size, std::forward<G>(gen));
if (size > N + 16) return new_plus<T, G, N + 17>(size, std::forward<G>(gen));
if (size > N + 8) return new_plus<T, G, N + 9>(size, std::forward<G>(gen));
if (size > N + 4) return new_plus<T, G, N + 5>(size, std::forward<G>(gen));
if (size > N + 2) return new_plus<T, G, N + 3>(size, std::forward<G>(gen));
if (size > N + 1) return new_plus<T, G, N + 2>(size, std::forward<G>(gen));
if (size > N) return new_plus<T, G, N + 1>(size, std::forward<G>(gen));
// here N == size so it's time to new[]:
return [gen = std::forward<G>(gen)]<std::size_t... I>(std::index_sequence<I...>) {
return new T[N]{((void)I, gen())...};
}(std::make_index_sequence<N>{});
}
}