我正在使用哈希表,并且我有一个保存我的键值的桶类型,所以我可以将它们保存在联合中并保持未初始化以避免为它们要求DefaultConstructible:
template <class K, class V>
struct bucket {
bucket() : hash(SENTINEL) {}
bucket(uint64_t hash, K&& k, V&& v)
: hash(hash), key(std::forward(k)), val(std::forward(v)) {}
<copy constructors>
~bucket() {
if (hash != SENTINEL) {
key.~K();
val.~V();
}
}
uint64_t hash;
union { K key; }
union { V key; }
};
Run Code Online (Sandbox Code Playgroud)
那么,我的问题就像是=运算符,我通常会用复制和交换的习语来编写:
bucket& operator =(bucket other) {
using std::swap;
swap(hash, other,hash);
swap(key, other.key);
swap(val, other.val);
}
Run Code Online (Sandbox Code Playgroud)
这是否仍然安全,即使使用了楔形键和val?
这甚至更早失败:读取union除最后一个成员之外的成员是UB .
如果您尚未为任何成员分配值,则无论是何种类型或任何"读取未经注册的变量"规则,您也无法读取任何成员.
正如我在评论中提到的,避免默认可构造要求的正确方法是使用placement new.