Сравнение равенства союзов?

Существует ли стандартный (или, по крайней мере, безопасный) способ сравнения союзов на равенство в C и / или C ++? Я ожидаю, что побитовое сравнение будет полезно в ряде сценариев несмотря на последнего назначенного члена в каждом союзе; например, конкретный битовый шаблон может быть зарезервирован для обозначения «значение неинициализировано», и было бы полезно иметь возможность проверить, не является ли инициализация неинициализированным, без необходимости указывать «активный» член.

Пример в C ++ (хотя я думаю, что концепция распространяется на C с использованием функций, не являющихся членами):

union MyData
{
public:
// Assume I'm compiling this on a platform where the size of `int`
// exceeds the size of `char*`, or that I'm using some combination
// if `#ifdef`s or similar to ensure that my numeric type is sufficiently
// large, or that I include an extra member that is known to be
// exactly the size of the larger member, just for the sake of
// comparison.
int int_member;
char* ptr_member;

bool isInitialized() const
{
return (*this != INVALID_VAL);
}

bool operator==(MyData const& rhs)
{
return / * ??? */;
}

private:
constexpr MyData INVALID_VAL { /* ??? */ };
}

// ... later, in client code...

MyData d;
bool initialized{d.isInitialized()};  // false
d.ptr_member = new char[32];
bool initialized{d.isInitialized()};  // true

Вот, INVALID_VAL вероятно, может быть определено путем установки int_member до максимального отрицательного значения int, поскольку это неравномерное значение, поэтому оно не будет находиться на границе слова и, следовательно, вряд ли когда-либо будет присвоено char* член (при условии, что задания обычно приходят непосредственно от new).

Одна возможная реализация operator== было бы просто:

return int_member == rhs.int_member;

Хотя неизвестно, int_member является «активным» членом, я ожидаю, что это будет безопасно, потому что я не вижу причин, почему статическое приведение от char* в int должен потерпеть неудачу или быть проблемным. Это верно?

Если эта реализация является небезопасно, что-то вроде следующего должно быть возможным (конечно, с использованием приведения в стиле C в C):

return static_cast<void*>(*this) == static_cast<void*>(rhs);

…хотя конечно если MyData больше, чем размер указателя, вам придется начать возиться с sizeof чтобы сделать эту работу.

Кто-нибудь делает это? Является ли первая (более простая) реализация безопасной? есть ли смысл не сделать это?

2

Решение

Я думаю, что лучшим подходом было бы заключить ваш союз в класс или структуру с сохранением поля enum, которое было последним членом, к которому обращались, например,

class MyData {
enum {
unintialized, int_member, ptr_member
} last_member = unintialized;

union {
int int_member;
char* ptr_member;
} union_fields;

public:
bool isInitialized() const
{
return last_member != unintialized;
}
};

Инициализация в классе last_member работает, если у вас есть C ++ 11, в противном случае просто инициализируйте его в конструкторе по умолчанию.

Создайте методы доступа для двух полей и установите last_member соответственно, было бы также хорошо добавить проверки в методы доступа, обеспечивающие доступ только к «активному члену».

3

Другие решения

Конечно это небезопасно.

Вы не можете предположить, что int имеет такой же размер, как char *, например. Также может быть дополнение, которое часто бывает случайным по содержанию.

1

По вопросам рекламы [email protected]