gct
gct

Reputation: 14563

Is it safe to swap uninitialized members in C++?

I'm working on a hash table, and I've got a bucket type that holds my key values, so I can hold them in unions and leave them uninitialized to avoid requiring DefaultConstructible for them:

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; }
};

My question, then, is something like the = operator, which I would usually write with the copy-and-swap idiom:

bucket& operator =(bucket other) {
     using std::swap;
     swap(hash, other,hash);
     swap(key,  other.key);
     swap(val,  other.val);
}

Is this still safe, even with unitialized key and val?

Upvotes: 1

Views: 227

Answers (1)

Baum mit Augen
Baum mit Augen

Reputation: 50053

This fails even earlier: It is UB to read a union member other than the one last assigned to.

If you have not assigned a value to any member, you also can't read any member, regardless of the type or any "reading uninitalized variables" rules.


As I mentioned in the comments, the correct way to avoid the default constructible requirement would be using placement new.

Upvotes: 5

Related Questions