使用 reinterpret_cast 访问私有数据

Ayx*_*xan 8 c++ language-lawyer

这似乎成功编译和访问私有数据。这是定义明确的行为吗?

#include <iostream>
#include <string>

using std::string;

class foo {
    string private_data = "Hello World";
};

int main()
{
    foo f;
    auto* pprivate_data = reinterpret_cast<string*>(&f);
    std::cout << *pprivate_data << '\n';
}
Run Code Online (Sandbox Code Playgroud)

这个问题有点相似,但我相信它没有解决我的问题。

Sto*_*ica 9

不,行为未定义。要使这样的 areintepret_cast有意义,这两个对象必须可以相互转换

[基础.化合物]

4两个对象 a 和 b 是指针可转换的,如果:

  • 它们是同一个对象,或者
  • 一个是联合对象,另一个是该对象的非静态数据成员([class.union]),或
  • 一个是标准布局类对象,另一个是该对象的第一个非静态数据成员,或者,如果该对象没有非静态数据成员,则是该对象的任何基类子对象 ([class.mem]) , 或者
  • 存在一个对象 c 使得 a 和 c 是指针可相互转换的,而 c 和 b 是指针可相互转换的。

如果两个对象是指针可互转换的,则它们具有相同的地址,并且可以通过 a 从指向另一个的指针获取指向一个的指针reinterpret_­cast。[ 注意:一个数组对象和它的第一个元素是指针不可转换的,即使它们有相同的地址。— 尾注 ]

唯一可能适用的项目是关于标准布局类的项目。如果我们查阅该定义,我们会看到

[类.prop]

3类 S 是标准布局类,如果它:

  • 没有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员,
  • [...]

有一个紧迫的问题。对象的任何非静态数据成员本身必须是标准布局。不能保证std::string是标准布局类型。所以行为是未定义的。


eca*_*mur 8

是的,这是细的条件下std::string(因此class foo)是标准布局(它在的libstdc ++,++的libc和MSVC STL)。每个class.mem/26

如果标准布局类对象具有任何非静态数据成员,则其地址与其第一个非静态数据成员的地址相同 [...] [注意:该对象及其第一个子对象是指针可相互转换的( [basic.compound], [expr.static.cast])。— 尾注]

basic.compund/4

两个对象 a 和 b 是指针可互转换的,如果: [...]

  • 一个是标准布局类对象,另一个是该对象的第一个非静态数据成员 [...]

如果两个对象是指针可互转换的,则它们具有相同的地址,并且可以通过 reinterpret_cast 从指向另一个的指针获取指向一个的指针。

显然,这只适用于第一个非静态数据成员。