Почему следующий код вызывает ошибку сегментации?
#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
Доступ запрещен 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
первый член.