创建不可默认构造的虚拟对象 class
Create dummy object of non-default-constructible class
tl;dr:我想构造一个 class ListEntry 包含泛型类型 Value 的成员,但是Value 不是默认可构造的,ListEntry 不知道如何构造它。我永远不会访问这个 Value 成员,所以它没有被初始化也没关系。
我为什么要这样做
我正在实现一个大致类似于以下内容的双链表
template<class Value>
class ListEntry {
Value value;
ListEntry<Value> *prev;
ListEntry<Value> *next;
};
template<class Value>
class List {
ListEntry<Value> sentinel;
};
列表条目之间的链接始终形成一个封闭的圆圈,标记将最后一个列表元素连接到第一个列表元素。 sentinel 对象初始化为 sentinel.prev = &sentinel 和 sentinel.next = &sentinel.
这样,我摆脱了很多特殊情况,而且我永远不必检查 nullptr,因为没有空指针。将元素添加到列表的末尾(在最后一个元素和标记之间)不是特例,但与在两个实际元素之间的列表中间添加一个元素相同。
所以在所有真实列表条目中,值字段将包含列表条目的实际值。对于他们,我可以通过在构造函数中给它一个 Value 对象来初始化 ListEntry,所以我不需要 Value 是默认可构造的。在哨兵中,永远不会访问值字段。但不幸的是,由于 Value 不是默认可构造的,编译器不允许我创建哨兵对象。
我可以使 ListEntry 中的值成员成为指针,boost::optional 或类似的东西。由于性能问题,我不喜欢这个。
关于如何在 ListEntry 中存储 Value 而无需 performance/memory 成本且不需要 Value 的任何想法是默认可构造的?在我看来,必须有一种方法可以在不调用其构造函数的情况下获取 Value 对象。
使用原始缓冲区和新位置:
template<class Value>
class ListEntry {
alignas(Value) char storage[sizeof(Value)];
ListEntry<Value> *prev;
ListEntry<Value> *next;
};
构建 Value
:
new (entry->storage) Value(/* params */);
破坏 Value
:
reinterpret_cast<Value*>(entry->storage)->~Value();
您可以将其拆分为基础 class 和节点 class,例如
class ListEntryBase {
ListEntryBase *prev;
ListEntryBase *next;
};
template<class Value>
class ListEntry : public ListEntryBase {
Value value;
};
template<class Value>
class List {
ListEntryBase sentinel;
};
这样可以避免创建不需要的值,同时 Value
不需要是默认可构造的。
tl;dr:我想构造一个 class ListEntry 包含泛型类型 Value 的成员,但是Value 不是默认可构造的,ListEntry 不知道如何构造它。我永远不会访问这个 Value 成员,所以它没有被初始化也没关系。
我为什么要这样做
我正在实现一个大致类似于以下内容的双链表
template<class Value>
class ListEntry {
Value value;
ListEntry<Value> *prev;
ListEntry<Value> *next;
};
template<class Value>
class List {
ListEntry<Value> sentinel;
};
列表条目之间的链接始终形成一个封闭的圆圈,标记将最后一个列表元素连接到第一个列表元素。 sentinel 对象初始化为 sentinel.prev = &sentinel 和 sentinel.next = &sentinel.
这样,我摆脱了很多特殊情况,而且我永远不必检查 nullptr,因为没有空指针。将元素添加到列表的末尾(在最后一个元素和标记之间)不是特例,但与在两个实际元素之间的列表中间添加一个元素相同。
所以在所有真实列表条目中,值字段将包含列表条目的实际值。对于他们,我可以通过在构造函数中给它一个 Value 对象来初始化 ListEntry,所以我不需要 Value 是默认可构造的。在哨兵中,永远不会访问值字段。但不幸的是,由于 Value 不是默认可构造的,编译器不允许我创建哨兵对象。
我可以使 ListEntry 中的值成员成为指针,boost::optional 或类似的东西。由于性能问题,我不喜欢这个。 关于如何在 ListEntry 中存储 Value 而无需 performance/memory 成本且不需要 Value 的任何想法是默认可构造的?在我看来,必须有一种方法可以在不调用其构造函数的情况下获取 Value 对象。
使用原始缓冲区和新位置:
template<class Value>
class ListEntry {
alignas(Value) char storage[sizeof(Value)];
ListEntry<Value> *prev;
ListEntry<Value> *next;
};
构建 Value
:
new (entry->storage) Value(/* params */);
破坏 Value
:
reinterpret_cast<Value*>(entry->storage)->~Value();
您可以将其拆分为基础 class 和节点 class,例如
class ListEntryBase {
ListEntryBase *prev;
ListEntryBase *next;
};
template<class Value>
class ListEntry : public ListEntryBase {
Value value;
};
template<class Value>
class List {
ListEntryBase sentinel;
};
这样可以避免创建不需要的值,同时 Value
不需要是默认可构造的。