Я хочу использовать строку внутри Union. , если я напишу, как показано ниже
union U
{
int i;
float f;
string s;
};
Компилятор выдает ошибку, говоря, что U :: S имеет конструктор копирования.
Я прочитал другой пост об альтернативных способах решения этой проблемы. Но я хочу знать, почему компилятор вообще не позволяет этого?
РЕДАКТИРОВАТЬ: @KennyTM: В любом союзе, если член инициализирован, другие будут иметь значения мусора, если ни один не инициализирован, все будут иметь значения мусора. Я думаю, что tagged union просто обеспечивает некоторый комфорт для доступа к действительным значениям от Union. Ваш вопрос: как вы или компилятор пишете конструктор копирования для указанного выше объединения без дополнительной информации? sizeof (string) дает 4 байта. На основе этого компилятор может сравнить размеры других членов и выделить наибольшее выделение (4 байта в нашем примере). Длина внутренней строки не имеет значения, потому что она будет храниться в отдельном месте.Пусть строка будет любой длины. Все, что нужно знать Union, - это вызвать конструктор копирования строкового класса со строковым параметром. Каким бы способом компилятор ни обнаружил, что конструктор копирования должен быть вызван в обычном случае, аналогичный метод, которому следует следовать, даже если строка находится внутри Union. Итак, я думаю, что компилятор мог бы выделить 4 байта. Затем, если какая-либо строка присваивается s, тогда строковый класс позаботится о выделении и копировании этой строки, используя свой собственный распределитель. Так что шансов на повреждение памяти тоже нет.
Разве строка не существовала во время разработки Union в компиляторе? Так что ответ мне до сих пор не ясен. Я новичок на этом сайте, если что-то не так, пожалуйста, извините меня.
Подумайте об этом. Как компилятор узнает, какой тип находится в объединении?
Не знает. Основная операция объединения - это поразрядное приведение. Операции со значениями, содержащимися в объединениях, безопасны только тогда, когда каждый тип может быть заполнен мусором. std :: string
не может, потому что это приведет к повреждению памяти. Используйте boost :: option
или boost :: any
.
Из спецификации C++ §9. 5.1:
Объект класса с нетривиальным конструктором, нетривиальным конструктором копирования, нетривиальным деструктором или нетривиальным оператором присвоения копий не может быть членом объединения.
Причина этого правила в том, что компилятор никогда не узнает, какой из деструкторов/конструкторов вызывается, поскольку он никогда не знает, какой из возможных объектов находится внутри объединения.
Потому что наличие класса с нетривиальным конструктором (copy /) в объединении не имеет смысла. Предположим, у нас есть
union U {
string x;
vector<int> y;
};
U u; // <--
. Если бы U была структурой, u.x
и u.y
были бы инициализированы пустой строкой и пустым вектором соответственно. Но у членов профсоюза один и тот же адрес. Таким образом, если инициализируется u.x
, u.y
будет содержать недопустимые данные, и наоборот. Если они оба не инициализированы, их нельзя использовать. В любом случае, объединение этих данных не может быть легко обработано, поэтому C ++ 98 предпочитает отрицать это: (§9.5 / 1):
Объект класса с нетривиальным конструктором (12.1), Нетривиальный конструктор копирования (12.8), нетривиальный деструктор (12.4) или нетривиальный оператор присваивания копии (13.5.3, 12.8) не могут быть членом объединения, как и массив таких объектов.
В C ++ 0x это правило было ослаблено (§9.5 / 2):
Максимум один нестатический член данных объединения может иметь фигурную скобку или равный инициализатор . [ Примечание: , если какой-либо нестатический член данных объединения имеет нетривиальный конструктор по умолчанию (12.1), конструктор копирования (12.8), конструктор перемещения (12.8), оператор присваивания копии (12.8), перемещение оператор присваивания (12.8) или деструктор (12.4), соответствующая функция-член объединения должна быть предоставлена пользователем, иначе она будет неявно удалена (8.4.3) для объединения. - конечное примечание ]
, но по-прежнему невозможно создать (исправить) конструкторы / деструкторы для объединения, например как вы или компилятор пишете конструктор копирования для указанного выше объединения без дополнительной информации? Чтобы убедиться, что член объединения активен, вам понадобится помеченное объединение , и вам нужно будет обрабатывать построение и разрушение вручную, например
struct TU {
int type;
union {
int i;
float f;
std::string s;
} u;
TU(const TU& tu) : type(tu.type) {
switch (tu.type) {
case TU_STRING: new(&u.s)(tu.u.s); break;
case TU_INT: u.i = tu.u.i; break;
case TU_FLOAT: u.f = tu.u.f; break;
}
}
~TU() {
if (tu.type == TU_STRING)
u.s.~string();
}
...
};
Но, как упомянул @DeadMG , это уже реализовано как boost :: variant
или boost :: any
.
В C ++ 98/03 члены объединения не могут иметь конструкторов, деструкторов, виртуальных функций-членов или базовых классов.
Таким образом, вы можете использовать только встроенные типы данных или POD
Обратите внимание, что в C ++ 0x это меняется: Unrestricted unions
union {
int z;
double w;
string s; // Illegal in C++98, legal in C++0x.
};