使用reinterpret_cast访问私有数据

8

代码似乎可以编译并成功访问私有数据。这是定义良好的行为吗?

#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';
}

这个问题有点类似,但我认为它没有回答我的问题。


只要foo是POD,它就应该足够长。 - Kostas
它怎么可能不是100%的工作呢?你为什么还要使用class关键字呢? - user2039981
1
@super 当然它在实践中可以正常工作。我想知道它是否在技术上定义良好,你可以看到它是由“语言律师”标签打上的。 - Ayxan Haqverdili
这种情况什么时候会发生? - user2039981
如果foo包含多个成员,我几乎可以确定将完整的foo实例重新解释为其成员类型之一时,会违反严格别名规则。 - Fareanor
4
我想那个给负评的人没有理解这个问题,语言律师的问题并不一定是关于实际编写代码的,因为我认为这个问题并没有什么问题。 - 463035818_is_not_a_number
2个回答

9
不,这种行为是未定义的。为了使这样的 reinterpret_cast 有意义,这两个对象必须是可互换的。

[basic.compound]

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

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

如果两个对象是指针可互换的,则它们具有相同的地址,可以通过reinterpret_­cast从一个指针获得另一个指针。[注意:数组对象及其第一个元素虽然具有相同的地址,但它们不是指针可互换的。—end note]

唯一可能适用的是有关标准布局类的那个弹药。 如果我们查看该定义,我们会发现,

“[class.prop]”
“{{link1:3}}如果一个类S符合以下条件,则为标准布局类:”
  • 没有非静态数据成员是非标准布局类(或此类类型的数组)或引用,
  • [...]

这里有一个直接的问题。 对象的任何非静态数据成员本身必须是标准布局。 无法保证std :: string是标准布局类型。 因此,行为未定义。


一定要喜欢未定义行为! - user2039981
1
@Ayxan - 那么如果我们查阅**[class.prop]**中的列表,foo就是标准布局。所以转换变得明确定义了。 - StoryTeller - Unslander Monica
1
@Evg - 这是无关紧要的。您始终可以通过合法获得的指针修改private_data。它是f的子对象并不重要。问题在于指针获取的方式是否合法。 - StoryTeller - Unslander Monica
@Evg - 不,我们正在访问 f.private_data - StoryTeller - Unslander Monica
1
@Fareanor - 是的,我们在这里试图进行转换。标准说我们可以获得正确的地址,就像使用&f.private_data来获取地址一样。 - StoryTeller - Unslander Monica
显示剩余9条评论

8

是的,在条件为std::string(因此class foo)是标准布局时,这是可以的(在libstdc++、libc++和MSVC STL中它)。根据class.mem/26

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

basic.compund/4

如果两个对象a和b是“指针可互转的”,那么:

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

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接