C++ - 结构体和类的填充方式

4

为了获得最大的性能(良好的内存对齐),我总是在C中填充我的结构体。

// on a x86_64 
struct A {

 int64_t z;
 int32_t x;
 int16_t y;
 // we don't care the uint8_t position, as they are 1 byte wide.
 uint8_t s[8];
 uint8_t t[4];

}

但是如果我决定走c++的路线,为了其他目的创建一个对象,我需要一个类:

class B {

   B(){}
  ~B(){}

 public:
   int64_t a;
   int8_t  b;

 private:
   int32_t c;

//methods...
}

那么,c就不再对齐了。

有没有方法可以避免这种情况(多个标签):

class B {

  B(){}
  ~B(){}

 public:
   int64_t a;

 private:
   int32_t c;

 public:
   int8_t  b;

}

在一些 CPU 上,对齐很重要。谢谢。


4
我怀疑这个班级没有对齐。 - user2249683
重点不在于类,而在于其中的变量。我找不到任何说明它是否自动对齐和正确组织的内容。我不想丢失太多字节。 - Kroma
5
我怀疑班上的成员意见不一致。 - user2249683
1
难道这不是在耗尽所有其他优化的可能性之前,你都不应该考虑对代码进行的操作吗?首先编写易读的良好代码,然后再找出需要裁减的部分。 - NathanOliver
2
请参见:http://stackoverflow.com/questions/4883655/access-specifier-in-c/4883764#4883764 - NathanOliver
显示剩余5条评论
2个回答

2

没错。把所有状态都放在一个结构体中,按您希望的方式对齐和填充。最好不要在结构体上使用成员函数,保持它的简单性。该类保存此结构体的私有实例。类成员函数直接作用于这个状态。

这应该足够了。而且你可以获得状态和函数之间的清晰分离,这总是很好的。通常与类中的set/get函数一起使用,除非您特别喜欢使用不一致的语法来调用函数和访问状态。

Alignas也可能会引起兴趣。


那是一个有趣的想法,Jon。 - Kroma
1
你可以直接在类中这样做。按适当顺序将所有成员设为私有,并使用函数访问它们。结果是相同的,而且你不必一直解除引用额外的层级(没有语义)。 - vlad_tepesch

0

你的努力完全是浪费时间。编译器会自行对齐(除非你明确告诉它不这样做)。它会在成员之间插入字节,并在结构体末尾插入足够的字节,以使其整体大小为结构体对齐规则的倍数。

你的努力也是适得其反的。如果为其他架构编译并使用其他对齐规则呢?那么编译器会在你的填充字节中再插入填充字节。

只有当数据需要在编译器或架构范围之外交换时,明确的对齐和紧凑的结构才有意义。


错误。你没有意识到有时我们需要为结构体/类设置正确的对齐方式和最小尺寸。 - Kroma
你对编译器为了性能而正确地对齐内容的说法是正确的,这也是 OP 所问的,但其他人可能仍然希望执行该任务以节省由填充导致的内存损失。 - KABoissonneault
1
填充有时非常重要 - 将原子变量放置在不同的缓存行上以防止虚假共享是我想到的主要示例。不幸的是,这往往是特定于平台的。 - Jon Chesterfield
@Kroma 如果你想要最小的尺寸,那么你必须改变成员的顺序。手动填充无法帮助你以任何方式节省内存。 - vlad_tepesch
@vlad_tepesch:是的,我知道!谢谢。 - Kroma

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