简体   繁体   English

创建非默认可构造类的虚拟对象

[英]Create dummy object of non-default-constructible class

tl;dr: I want to construct a class ListEntry containing a member of a generic type Value , but Value is not default constructible and ListEntry doesn't know how to construct it. tl; dr:我想构造一个包含泛型类型Value成员的ListEntry类,但Value不是默认构造的, ListEntry不知道如何构造它。 I will never access this Value member, so it doesn't matter that it isn't initialized. 我永远不会访问这个Value成员,所以没有初始化它并不重要。

Why I'm doing this 为什么我这样做

I'm implementing a double linked list roughly similar to the following 我正在实现一个大致类似于以下内容的双链表

template<class Value>
class ListEntry {
  Value value;
  ListEntry<Value> *prev;
  ListEntry<Value> *next;
};
template<class Value>
class List {
  ListEntry<Value> sentinel;
};

The links between the list entries always form a closed circle where the sentinel connects the last list element to the first list element. 列表条目之间的链接总是形成一个闭合的圆圈,其中sentinel将最后一个列表元素连接到第一个列表元素。 The sentinel object is initialized with sentinel.prev = &sentinel and sentinel.next = &sentinel. 使用sentinel.prev =&sentinel和sentinel.next =&sentinel初始化sentinel对象。

This way, I get rid of a lot of special cases and I never have to check for nullptr because there are no null pointers. 这样,我摆脱了很多特殊情况,我永远不必检查nullptr,因为没有空指针。 Adding an element to the end of the list (between the last element and the sentinel) is not a special case but the same as adding an element to the middle of the list between two real elements. 将元素添加到列表的末尾(在最后一个元素和sentinel之间)不是特殊情况,但与在两个真实元素之间的列表中间添加元素相同。

So in all real list entries, the value field will contain the actual value of the list entry. 因此,在所有实际列表条目中,值字段将包含列表条目的实际值。 For them, I can initialize ListEntry by giving it a Value object in its constructor, so I don't need Value to be default constructible. 对于它们,我可以通过在其构造函数中赋予它一个Value对象来初始化ListEntry ,因此我不需要Value是默认的可构造的。 In the sentinel, the value field will never be accessed. 在哨兵中,永远不会访问值字段。 But unfortunately, since Value is not default constructible, the compiler doesn't let me create the sentinel object. 但不幸的是,由于Value不是默认构造的,编译器不允许我创建sentinel对象。

I could make the value member in ListEntry a pointer, boost::optional or something similar. 我可以使ListEntry中的value成员成为指针,boost :: optional或类似的东西。 I don't like this due to performance issues though. 由于性能问题,我不喜欢这样。 Any ideas on how to store Value in ListEntry without performance/memory costs and without needing Value to be default constructible? 关于如何在没有性能/内存成本的情况下在ListEntry中存储Value并且不需要Value可默认构造的任何想法? It seems to me like there must be a way of getting a Value object without calling its constructors. 在我看来,必须有一种获取Value对象而不调用其构造函数的方法。

Use a raw buffer and placement new : 使用原始缓冲区和新位置:

template<class Value>
class ListEntry {
  alignas(Value) char storage[sizeof(Value)];
  ListEntry<Value> *prev;
  ListEntry<Value> *next;
};

Constructing the Value : 构建Value

new (entry->storage) Value(/* params */);

Destructing the Value : 破坏Value

reinterpret_cast<Value*>(entry->storage)->~Value();

You can split this into a base class and a node class, eg 您可以将其拆分为基类和节点类,例如

class ListEntryBase {
    ListEntryBase *prev;
    ListEntryBase *next;
};

template<class Value>
class ListEntry : public ListEntryBase {
    Value value;
};

template<class Value>
class List {
    ListEntryBase sentinel;
};

This way you avoid creating an unneeded value and at the same time Value need not be default constructible. 这样您就可以避免创建不需要的值,同时Value不必是默认构造。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何正确初始化非默认可构造的类成员? - How to properly initialize non-default-constructible class member? 移动具有非默认构造 class 保护的构造函数 - Move constructor with protection for non-default-constructible class 如何创建C ++ 11不可默认构造的分配器? - How to create a C++ 11 non-default-constructible allocator? 如何初始化不可默认构造的不可复制对象的元组? - How to initialize a tuple of non-default-constructible not-copyable objects? 使用非默认可构造类型填充std :: array(无可变参数模板) - Populate std::array with non-default-constructible type (no variadic templates) 使用不可默认构造的映射值添加到 std::map - add to std::map with a non-default-constructible mapped value 初始化非默认可构造元素的 std::array? - Initializing an std::array of non-default-constructible elements? 使用 Boost.Python 导出非默认可构造类 - Exporting non-default-constructible classes with Boost.Python std::map emplace 不可移动不可复制非默认可构造类型 - std::map emplace non-movable non-copyable non-default-constructible type 如何初始化std :: array <T, 2> 其中T是不可复制的,非默认可构造的? - How to initialize an std::array<T, 2> where T is non-copyable and non-default-constructible?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM