防止在 C++ 中构造/初始化数组元素

Posted

技术标签:

【中文标题】防止在 C++ 中构造/初始化数组元素【英文标题】:Prevent construction/initialization of array elements in C++ 【发布时间】:2017-03-08 13:26:50 【问题描述】:

我有以下声明(是的,它使用运行时数组长度扩展)

Iterator traversal_stack[depth]; 

我的问题是编译器试图初始化数组成员。事实上,这段代码并没有编译通过,因为Iterator 没有公共的默认构造函数。虽然我了解这种行为的来源,但在我的情况下,它确实是不需要的,因为对数组的访问模式 保证:

    一个数组元素最多只能写入一次,并且 任何元素都不会被读取而不被写入。

任何违反此模式的行为都意味着算法被搞砸了。下面是一个伪代码,说明了如何使用数组(它本质上是一个经过高度优化的堆栈,用于遍历平衡树)

Iterator traversal_stack[depth]; 
auto current_node = root;
auto current_level = 0;

// traverse the tree, looking for a suitable insertion point
// within every node, record visited nodes (vie the iterator struct)
while(current_level < depth) 
   // find the optimal insertion entry (pointed to by the iterator) 
   auto iter = as_branch(current_node).iterate();
   iter = find_best_insertion_point(iter, to_inserted_object);

   // record the visited node in the stack
   // a value is pushed onto the stack exactly  once!
   traversal_stack[current_level] = iter;

   // get to the next level of the tree
   current_node = iter.node_for_entry();
   current_level += 1;


// ... insert the data into the found terminal node

// now unroll the stack, adjusting the node metadata
current_level -= 1;
while(current_level >= 0) 
  // the element of the array is necessarily initialized
  // by assignment in the previous loop
  auto iter = traversal_stack[current_level];
  insertion_state = adjust_node_metadata_for(iter);

  current_level -= 1;

我知道我可以只提供默认构造函数并完成它,但我真的很想避免它。除了可能(但可能不太重要)的性能考虑之外,默认构造函数的最大问题是它必须引入某种默认的无效状态,从而在很大程度上弄乱了迭代器语义。

所以,我的问题是:我可以这样声明数组,使值完全未定义吗?如果解决方案特定于使用最新的 C++1z 草案 + 自定义扩展的 Clang,我可以。

【问题讨论】:

请提供一些实际代码,也许是简化的测试用例,来演示您在说什么,以便我们更容易理解您要做什么。 为什么不使用std::vector 并根据需要添加Iterators? 另外,std::vector 并不慢,它和数组一样快(因为它内部是一个数组),而且它完全符合您的要求。它使用malloc 分配其数组以防止构造函数运行,然后根据需要执行就地构造。 @MrMobster std::vector 不会运行 malloc 数千次。只需调用std::vector::reserve,它只会为整个数组调用一次malloc 如果您知道最大尺寸,那么也许您可以在算法函数中使用thread_local static 数组?那应该是快速且线程安全的。最好不要关心函数入口中包含的内容。 【参考方案1】:

如果你真的想使用 VLA 和未初始化的对象。

一种方法是使用 std::aligned_storage 创建未初始化的内存块,然后将其转换为对数组的引用。

#include <type_traits>

struct Iterator 
  Iterator() = default;
;

int main() 
  int length = 10;
  std::aligned_storage_t<sizeof(Iterator), alignof(Iterator)> memory_blocks[length];
  auto &array = reinterpret_cast<Iterator (&)[length]>(memory_blocks);

  return 0;

【讨论】:

这是迄今为止唯一试图回答我的问题的答案。感谢std::aligned_storage_t,我不知道。但不应该是typename std::aligned_storage_t&lt;sizeof(Iterator), alignof(Iterator)&gt;::type吗?

以上是关于防止在 C++ 中构造/初始化数组元素的主要内容,如果未能解决你的问题,请参考以下文章

C++中数组的构造函数初始化列表

C++对象数组与对象指针

如何在c ++中的类构造函数中将整个数组初始化为单个元素

在 C++ 类中初始化二维数组

函数调用或构造函数调用中的 C++ 数组初始化

C++ 在构造函数中初始化数组