部分初始化结构的正确方法是什么?
What's the right way to partially initialize a struct?
对于用户定义的分配器,分配单元之间的关系必须在开始时构造,而元素的内存space应该保持未初始化。
一个简单的演示:
template <typename T>
struct Node {
T _item;
Node* _prev;
Node* _next;
};
template <typename T, typename ParentAllocator>
class MyAllocator {
using Allocator = std::allocator_traits<ParentAllocator>::rebind_alloc<Node<T>>;
Allocator _allocator;
Node<T> _header;
/* ... */
public:
MyAllocator()
: _allocator()
{
_header._prev = &_header;
_header._next = &_header;
// leaving `_item` uninitialized
}
T* allocate(/*one*/) {
auto* newNode = _allocator.allocate(1);
newNode->_prev = &_header;
newNode->_next = _header._next;
// leaving `_item` uninitialized
/* ... */
return &(newNode->_item);
}
};
Node
未初始化,而是直接为其成员初始化,但不是全部。
我的问题是:
-
_header
和 _next
是否确实按预期部分初始化,即使 T
(正常和 explicit
一个)的默认构造函数被删除。
- 我实施得当吗?
- 如果不是,正确的方法是什么?
您需要修改 Node
使其默认可构造,并且您不想默认构造 T
即使它有默认构造函数。因此,您可以将 T _item
替换为:
std::aligned_storage<sizeof(T), alignof(T)> _item;
或者在 C++23 中,因为 std::aligned_storage
已弃用:
alignas(T) std::byte _item[sizeof(T)];
这将为您提供所需的存储 space,并适当对齐,然后您将使用新放置在该存储中构建 T
。您还需要在销毁每个 Node
.
之前或销毁期间显式调用 ~T()
显示基础知识的演示,肯定不完整或未测试:https://godbolt.org/z/bGaKWb3de
对于用户定义的分配器,分配单元之间的关系必须在开始时构造,而元素的内存space应该保持未初始化。
一个简单的演示:
template <typename T>
struct Node {
T _item;
Node* _prev;
Node* _next;
};
template <typename T, typename ParentAllocator>
class MyAllocator {
using Allocator = std::allocator_traits<ParentAllocator>::rebind_alloc<Node<T>>;
Allocator _allocator;
Node<T> _header;
/* ... */
public:
MyAllocator()
: _allocator()
{
_header._prev = &_header;
_header._next = &_header;
// leaving `_item` uninitialized
}
T* allocate(/*one*/) {
auto* newNode = _allocator.allocate(1);
newNode->_prev = &_header;
newNode->_next = _header._next;
// leaving `_item` uninitialized
/* ... */
return &(newNode->_item);
}
};
Node
未初始化,而是直接为其成员初始化,但不是全部。
我的问题是:
-
_header
和_next
是否确实按预期部分初始化,即使T
(正常和explicit
一个)的默认构造函数被删除。 - 我实施得当吗?
- 如果不是,正确的方法是什么?
您需要修改 Node
使其默认可构造,并且您不想默认构造 T
即使它有默认构造函数。因此,您可以将 T _item
替换为:
std::aligned_storage<sizeof(T), alignof(T)> _item;
或者在 C++23 中,因为 std::aligned_storage
已弃用:
alignas(T) std::byte _item[sizeof(T)];
这将为您提供所需的存储 space,并适当对齐,然后您将使用新放置在该存储中构建 T
。您还需要在销毁每个 Node
.
~T()
显示基础知识的演示,肯定不完整或未测试:https://godbolt.org/z/bGaKWb3de