【问题标题】:Do public/private/protected change the arrangement of a struct in memory?public/private/protected 会改变内存中结构的排列吗?
【发布时间】:2018-10-10 16:29:04
【问题描述】:

编辑:我刚刚意识到一个更简单的方法来问这个问题:

给定以下两个结构:

class Thing {public: int a; public: int b; public: int c;}

class Thing {public: int a, private: int b; public: int c;}

对于这两个定义,成员 abc 是否保证在内存中的顺序相同?


老问题

假设我们在fileA.cpp 中有这段 C++ 代码:

class Thing
{
public:
    int a;
    double num;

    Thing()
    {
        b = 10;
    }

    float getB()
    {
        return b;
    }

private:
    float b;
    Thing * other;
}

void doSomething(Thing thing);

int main()
{
    Thing thing;
    doSomething(thing);
    std::cout << thing.b;
}

假设我们在fileB.cpp 中有这段代码:

class Thing
{
public:
    int a;
    double num;

    Thing()
    {
        b = 10;
    }

    float getB()
    {
        return b;
    }

    float b;

private:
    Thing * other;
}

void doSomething(Thing thing)
{
    thing.b = 30;
}

假设编译器不会抱怨,这段代码会按预期工作吗?也就是说,结构数据的排列是否独立于某些组件是公共的、私有的还是受保护的?

编辑:为了更明显,Thing 的两个定义之间的唯一区别是float b;fileA.cpp 中是私有的,但在fileB.cpp 中是公共的。

【问题讨论】:

  • 无论它们的布局如何,您都违反了单一定义规则。一个对象只能有一个定义。
  • 这就是friend 的目的,甚至更好地采用适当的面向对象设计来避免这个问题。
  • 是的,它会生成相同的代码

标签: c++ struct mismatch


【解决方案1】:

标准不做这样的保证。您仅对标准布局类有布局保证:

标准布局类是这样的类:

  • 没有非标准布局类(或此类类型的数组)或引用类型的非静态数据成员,
  • 没有虚函数 (10.3) 和虚基类 (10.1),
  • 对所有非静态数据成员具有相同的访问控制(第 11 条),
  • 没有非标准布局基类,
  • 在最派生类和最多一个基类中没有非静态数据成员 非静态数据成员,或没有具有非静态数据成员的基类,并且
  • 没有与第一个非静态数据成员相同类型的基类。

(C++14,[类]¶7)

如果一个类是标准布局,那么它的布局是很好定义的(并且两个具有布局兼容初始序列的标准布局类可以通过union 读取彼此的布局兼容成员)。

但是,情况并非如此,因为您在整个类中有不同的访问说明符。特别是,它明确指出

未指定不同访问控制的非静态数据成员的分配顺序

(C++14, [class.mem] ¶13)


话虽如此,我从未使用过任何利用标准提供的这种灵活性的现实世界编译器 - 我知道的每个编译器都使用访问说明符进行编译时检查,但完全忽略了它们就成员布局而言。

【讨论】:

  • 我不明白这样做的理由。通过这种灵活性可以实现什么?
  • @Martin:这对我来说也是个谜;我对此的唯一想法是,也许一些早期的实现将具有不同访问控制的成员存储在单独的列表中,然后以固定的顺序输出它们(例如,首先是所有公共的,然后是所有受保护的,然后是所有私有的),或者他们甚至是出于某种原因,在单独的子结构中的“基础”C 结构中输出,但所有这些假设似乎都遥不可及。
  • 想到的另一种可能性是,他们可能认为,鉴于使用访问说明符,类不再是 C 样式,因此受制于旧 API,编译器可以利用这个机会重新排序成员和减少填充,但即使这样似乎也不合理。
  • 这里可能有一个解释:stackoverflow.com/q/41407540/214671,类似于我的第一个想法(一些现有的实现根据访问说明符改变了布局)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-21
  • 2019-08-07
  • 1970-01-01
  • 2016-03-02
  • 2020-07-31
  • 2010-11-22
  • 1970-01-01
相关资源
最近更新 更多