防止在C ++

时间:2017-03-08 13:26:50

标签: c++ arrays constructor initialization clang

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

Iterator traversal_stack[depth]; 

我的问题是编译器尝试初始化数组成员。实际上,此代码无法编译,因为Iterator没有公共默认构造函数。虽然我理解这种行为来自哪里,但就我而言,它实际上是不受欢迎的,因为数组的访问模式 保证:

  1. 数组元素最多写入一次
  2. 没有被写入就不会读取任何元素。
  3. 此模式的任何违规都意味着算法搞砸了。下面是一个伪代码,说明了如何使用数组(它实际上是一个用于遍历平衡树的高度优化的堆栈)

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

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

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

1 个答案:

答案 0 :(得分:2)

如果你真的想使用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;
}