So I've been trying to create a discriminated union for my project. Coming from C, I thought it would be trivial... ;)
The structure is named Message
. It has a MessageType
and an inner union which holds either a MessageGet
or a MessageSet
.
enum MessageType {
MESSAGE_GET,
MESSAGE_SET
};
struct MessageGet {
std::string store_name;
std::vector<uint8_t> key;
};
struct MessageSet {
std::string store_name;
std::vector<uint8_t> key;
std::vector<uint8_t> value;
};
struct Message {
MessageType type;
uint64_t sender_id;
union U {
U() : get() {}
U(const U& other) {
get = other.get;
set = other.set;
}
~U() {}
U& operator=(const U& other) {
set = other.set;
get = other.get;
return *this;
}
MessageGet get;
MessageSet set;
} as;
Message() {}
~Message() {
switch (type) {
case MESSAGE_GET: {
as.get.~MessageGet();
break;
}
case MESSAGE_SET: {
as.set.~MessageSet();
break;
}
}
}
Message(MessageGet get, uint64_t sender_id) {
type = MESSAGE_GET;
as.get = get;
sender_id = sender_id;
}
Message(MessageSet set, uint64_t sender_id) {
type = MESSAGE_SET;
as.set = set;
sender_id = sender_id;
}
Message(const Message& other) {
type = other.type;
as = other.as;
sender_id = other.sender_id;
}
Message& operator=(const Message& other) {
type = other.type;
as = other.as;
sender_id = other.sender_id;
return *this;
}
};
The program crashes elsewhere in the code where I do something like this:
Message message(MessageGet {std::move(store_name), std::move(key)}, sender);
messages.push_back(message); // messages is a local std::vector<Message>
It doesn't crash with an exception - simply a crash.
I've managed to narrow it down to inside the Message
copy constructor. After that, have no clue what causes this. Ideas would be appreciated.
U(const U& other) {
get = other.get;
set = other.set;
}
This always sets set
last, making the value of get
invalid. When you set one of the members of a union, it invalidates all the others. That's what makes a union different from a struct.
Where you have:
as = other.as;
You have to change that to copy only the valid member.