防止在 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
并根据需要添加Iterator
s?
另外,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<sizeof(Iterator), alignof(Iterator)>::type
吗?以上是关于防止在 C++ 中构造/初始化数组元素的主要内容,如果未能解决你的问题,请参考以下文章