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