创建非默认可构造类的伪对象
Create dummy object of non-default-constructible class
tl;dr:我想构造一个类ListEntry,该类包含泛型类型Value的成员,但Value不是默认可构造的,而且List Entry不知道如何构造它。我永远不会访问这个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=&哨兵
这样,我就消除了很多特殊情况,而且我永远不必检查nullptr,因为没有null指针。将一个元素添加到列表的末尾(在最后一个元素和sentinel之间)并不是一种特殊情况,但与在两个实际元素之间的列表中间添加一个元素相同。
因此,在所有实际列表条目中,值字段将包含列表条目的实际值。对于它们,我可以通过在其构造函数中给Value对象来初始化ListEntry,所以我不需要Value是默认可构造的。在sentinel中,值字段永远不会被访问。但不幸的是,由于Value不是默认可构造的,编译器不允许我创建sentinel对象。
我可以使ListEntry中的值成员成为指针、boost::可选或类似的东西。不过,由于性能问题,我不喜欢这样。关于如何将值存储在ListEntry中而不需要性能/内存成本,也不需要将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 ListEntryBase {
ListEntryBase *prev;
ListEntryBase *next;
};
template<class Value>
class ListEntry : public ListEntryBase {
Value value;
};
template<class Value>
class List {
ListEntryBase sentinel;
};
这样可以避免创建不需要的值,同时Value
不必是默认可构造的。
- C++对象默认变量
- 在 C++ 中声明 const 对象需要用户定义的默认构造函数.如果我有一个可变成员变量,为什么不呢?
- 如何处理没有默认构造函数但在另一个构造函数中构造的对象?
- 在C++中使用默认构造函数初始化对象的不同方法
- 在没有默认构造函数的情况下创建的派生对象
- 使用默认构造函数初始化对象的不同方法
- 为什么指针对象没有调用默认构造函数
- 在没有默认构造函数时使用垃圾数据初始化对象
- 为什么对象默认初始化,但基元不在C++?
- 为什么在使用指针时不采用类成员的默认值,而不是直接实例化对象时?
- 为什么我的对象声明不调用默认构造函数?
- 如果普通默认构造函数不执行任何操作,为什么我们不能使用 malloc 创建平凡可构造的对象?
- 如何防止类中的类对象尝试在没有默认构造函数的情况下自动构造自身?
- 为什么用默认构造函数构造std::string对象时行为不同
- 声明成员对象而不调用其默认构造函数
- 可调用对象作为默认模板参数
- C++ 实例化新对象时不接受继承方法默认参数值
- 关于默认构造函数,对象初始化/使用C++ OOP
- C++ 创建不带默认构造函数的对象数组
- 在创建对象向量时,不为每个对象唯一调用默认对象构造函数