【问题标题】:How is access for private variables implemented in C++ under the hood?如何在 C++ 中实现对私有变量的访问?
【发布时间】:2012-07-14 19:10:43
【问题描述】:

编译器如何控制内存中变量的保护?内存中是否有与私有变量相关的标记位?它是如何工作的?

【问题讨论】:

  • 编译器=编译时,内存=运行时,差别很大

标签: c++ memory-management private-members data-protection


【解决方案1】:

如果您的意思是 private 实例成员,那么在运行时没有任何保护。所有保护都发生在编译时,如果你知道它们在内存中的布局,你总是可以得到一个类的私有成员。这需要了解平台和编译器,在某些情况下甚至可能取决于编译器设置,例如优化级别。

例如,在我的带有 GCC 4.6 的 Linux/x86-64 上,下面的程序完全符合您的预期。它绝不是可移植的,并且可能会在异国情调的编译器上打印出意想不到的东西,但即使是那些编译器也会有自己特定的方式来获取私有成员。

#include <iostream>

class FourChars {
  private:
    char a, b, c, d;

  public:
    FourChars(char a_, char b_, char c_, char d_)
      : a(a_), b(b_), c(c_), d(d_)
    {
    }
};

int main()
{
    FourChars fc('h', 'a', 'c', 'k');

    char const *p = static_cast<char const *>(static_cast<const void *>(&fc));

    std::cout << p[0] << p[1] << p[2] << p[3] << std::endl;
}

(复杂的转换是因为void* 是唯一可以转换任何指针的类型。然后void* 可以转换为char* 而无需调用strict aliasing rule。这可能是单reinterpret_cast 也是——实际上,我从不玩这种肮脏的把戏,所以我不太熟悉如何以最快的方式做到这一点:)

【讨论】:

  • @LuchianGrigore:为什么会这样?
  • @LuchianGrigore:我不这么认为。鉴于FourChars 必须至少有四个大小,打印它的前四个字节的结果具有依赖于实现,但不是未定义的行为。
  • @Mehrdad: reinterpret_cast&lt;&gt;?
  • @Vlad:我懒惰地使用了第一个有效的演员表。 C 风格的演员表会产生相同的结果。
  • 标准草案 N3242 9.2.20 指向标准布局结构对象的指针,使用 reinterpret_cast 适当转换,指向其初始成员(或者如果该成员是位字段,则指向单元它所在的位置),反之亦然。 [注意:因此,标准布局结构对象中可能有未命名的填充,但不是在其开头,这是实现适当对齐所必需的。尾注]
【解决方案2】:

编译器的工作是查看某些成员是私有的并禁止您使用它们。编译后它们与其他成员没有任何太大的不同。

有一个重要方面,因为数据成员不需要按照它们在类定义中出现的顺序排列在内存中,但它们是变量所必需的具有相同的访问级别。

【讨论】:

  • 从纯 C++ 的角度来看,stackoverflow.com/a/11486632/924727 的示例是 UB,因为可以通过某种方式填充变量以获得给定的对齐方式(因此,(&amp;a)[1] 不一定是 b,即使它被授予&amp;b &gt; &amp;a)。但是一旦给出了编译器并定义了编译选项,行为就不再依赖于执行。如果它有效,它将永远有效,如果它不...永远不会。事实上,它是不可移植的代码。
  • @EmilioGaravaglia:如果有填充,那么我的示例不显示 UB;它的行为只是依赖于实现。即,它将打印一些任意字节,但不会崩溃。是的,它是不可移植的,也许我应该更明确地说明这一点。
  • @larsmans:根据 UB 的 C++ 规范定义(因为 UB 本身已定义 :-) ),UB 并不一定意味着“崩溃”。它只是意味着“不是由 C++ 规范本身定义的”。如果它是“编译器依赖”,对于 ISO C++,是 UB。事实上,我们只是在说同一个概念,用不同的措辞,因为不同的视角(语言或编译器)
  • @EmilioGaravaglia:我知道 UB 是什么意思。我并不是说 UB 会导致崩溃,而是我的程序 不会 因为它不会 导致 UB。 C++ 标准还保留了一些实现定义的东西,编译器编写者可以选择实现什么行为。对齐就是一个例子;见标准草案 pp. 1318 ff。完整列表。
猜你喜欢
  • 2023-04-02
  • 1970-01-01
  • 2017-03-11
  • 2015-01-29
  • 2011-03-02
  • 2013-04-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多