为什么以这种方式访问联合中的指针会导致分段错误?

Why does access a pointer in a union this way cause segmentation fault?

本文关键字:指针 分段 错误 方式 访问 为什么      更新时间:2023-10-16

为什么下面的代码会导致分段错误?

#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,因为只有一个未指定值的初始化列表设置了第一个成员。

参见struct和union初始化中的"member lifetime"

U u{new std::string("A")};并不像您想的那样,因为它用调用new的值初始化了第一个成员。如果要设置正确的成员,请使用以下命令:

U u{.str_ptr=new std::string("A")};

——编辑——

这是gcc扩展,标准规定当用大括号括起来的初始化器初始化联合时,大括号只能包含该联合的第一个非静态数据成员的初始化子句。然后使用standard,你只能这样做:

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作为第一个成员。