我可以动态生成可以使用delete[]删除的连续的非默认可修改对象序列吗?

问题描述 投票:0回答:1

假设我有:

标识符 意义
T
非默认可构造类
gen
函数返回
T
n
size_t

现在,我想使用

n
在堆上连续生成
T
gen
对象 - 但这样我以后就可以销毁所有它们并在第一个地址上使用
delete[]
释放内存其中。

如果

T
是默认可构造的,那么这很简单:

T* my_t_objects = new[T](n);

之后我可以

delete[] my_t_objects
,鲍勃是我的叔叔。但是 - 当我无法默认构造时, array-new 将不起作用。有没有其他方法可以达到同样的效果...

  1. gen
    不带参数时,即
    T gen()
  2. gen
    采用索引时,即
    T gen(size_t)
    (在这种情况下我无法对所有元素进行相同的调用)?

我的直观想法是为

n
对象分配内存,然后随着索引的增加调用placement-
new
n
次;但如果我这样做,我有点怀疑从分配中获得的
delete[]
指针上的
T *
是否真的能做必要的事情。


备注:

  • 不,我不想使用
    std::vector<T>
    std::generate
    ,谢谢 :-)
  • 如果有帮助,
    gen()
    可以假设为
    noexcept
  • 假设
    T
    的演员都不是公开的,并且
    gen
    是朋友。
  • 仅在 C++20 或更高版本中有效的解决方案(由于here提到的考虑因素)很好,尽管我希望不依赖它,至少在实际用途中。
c++ dynamic-memory-allocation placement-new object-construction object-destruction
1个回答
0
投票

如果您不介意实例化大量函数,您可以将运行时值

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>{});
    }
}

演示

© www.soinside.com 2019 - 2024. All rights reserved.