在C++中交换未初始化的成员是否安全?

gct*_*gct 1 c++

我正在使用哈希表,并且我有一个保存我的键值的桶类型,所以我可以将它们保存在联合中并保持未初始化以避免为它们要求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?

Bau*_*gen 5

这甚至更早失败:读取union除最后一个成员之外的成员是UB .

如果您尚未为任何成员分配值,则无论是何种类型或任何"读取未经注册的变量"规则,您也无法读取任何成员.


正如我在评论中提到的,避免默认可构造要求的正确方法是使用placement new.

  • @ThomasRussell交换中的赋值将使联合的成员处于活动状态,但是评估函数参数会读取非活动成员,并且已经是UB. (2认同)