部分初始化结构的正确方法是什么?

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 未初始化,而是直接为其成员初始化,但不是全部。

我的问题是:

  1. _header_next 是否确实按预期部分初始化,即使 T(正常和 explicit 一个)的默认构造函数被删除。
  2. 我实施得当吗?
  3. 如果不是,正确的方法是什么?

您需要修改 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