Почему доступ к указателю в объединении таким образом вызывает ошибку сегментации?

Почему следующий код вызывает ошибку сегментации?

#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, поскольку список инициализаторов с одним неуказанным значением устанавливает первый член.

См. «Время жизни члена» под инициализация структуры и объединения.

5

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

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");
1

Указатель, возвращаемый функцией new, неявно преобразуется в тип первого члена, т.е. bool, Поскольку C ++ допускает это преобразование, ошибки не возникает.

// effectively what is happening.
U u{ new std::string("A") != 0 };

При использовании подобного объединения, вероятно, лучше быть явным и присваивать его членам напрямую. Но если вы действительно хотите сделать это так, просто сделайте str_ptr первый член.

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