Почему доступ к указателю в объединении таким образом вызывает ошибку сегментации?
Почему следующий код вызывает ошибку сегментации?
#include <string>
union U {
bool boolean;
double number;
std::string* str_ptr;
};
int main()
{
U u{new std::string("A")};
delete u.str_ptr;
return 0;
// return u.str_ptr->compare("A");
}
Я должен сказать, что не имеет значения, пытаюсь ли я вместо оператора return получить доступ к указателю каким-либо другим способом. Например заменить delete u.str_ptr; return 0;
с return u.str_ptr->compare("A");
Я все еще получаю ошибку сегментации.
В случае, если это зависит от конкретного компилятора, я использую g++ (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609
3 ответа
Доступ запрещен u.str_ptr
если это не был последний член, установленный в союзе. Но последний член в союзе boolean
, поскольку список инициализаторов с одним неуказанным значением устанавливает первый член.
Смотрите "время жизни члена" в разделе " Инициализация структуры и объединения".
U u{new std::string("A")};
не делает то, что вы думаете, как вы сказали ничего особенного, он инициализирует первый член со значением вызова new
, Если вы хотите установить правильный член, используйте следующее:
U u{.str_ptr=new std::string("A")};
---РЕДАКТИРОВАТЬ---
Это gcc
расширение говорит стандарт, когда объединение инициализируется инициализатором, заключенным в фигурные скобки, фигурные скобки должны содержать предложение инициализатора только для первого не статического члена данных объединения., Тогда со стандартным вы можете сделать только:
U u;
u.str_ptr = new std::string("A");
Указатель, возвращаемый функцией new, неявно преобразуется в тип первого члена, т.е. bool
, Поскольку C++ допускает это преобразование, ошибки не возникает.
// effectively what is happening.
U u{ new std::string("A") != 0 };
При использовании подобного объединения, вероятно, лучше быть явным и присваивать его членам напрямую. Но если вы действительно хотите сделать это так, просто сделайте str_ptr
первый член.