【发布时间】:2021-06-07 22:17:04
【问题描述】:
我有一个很小的实用程序类ObjectCounter,它没有虚拟方法和成员变量;它只包含一个构造函数和一个析构函数,它们分别递增和递减一个全局变量:
int _objectCount = 0; // global
class ObjectCounter
{
public:
ObjectCounter() {printf("DefaultCtor: count=%i\n", ++_objectCount);}
~ObjectCounter() {printf("Dtor: count=%i\n", --_objectCount);}
};
当我想跟踪我的程序在任何给定时间创建的另一个类的实例数时,我只需添加一个 ObjectCounter 作为该类的私有成员变量:
class SomeUserClass
{
public:
SomeUserClass() : _userData(0) {/* empty */}
~SomeUserClass() {/* empty */}
private:
ObjectCounter _objectCounter;
int64_t _userData;
};
(本来我会用那个类的子类ObjectCounter来代替,但是那样做就成了my DOxygen class-graphs unnecessarily complex,所以我改成一个私有成员变量)
今天我注意到将这个“空”私有成员变量添加到我的类对象通常会增加类对象的大小(由 sizeof() 报告)。例如,以下代码显示当我包含 _objectCounter 成员变量时,我的机器上的 sizeof(SomeUserClass) 从 8 增加到 16:
int main(int, char **)
{
SomeUserClass sc1;
printf("sizeof(SomeUserClass)=%zu\n", sizeof(SomeUserClass));
printf("sizeof(ObjectCounter)=%zu\n", sizeof(ObjectCounter));
return 0;
}
无论是否启用优化,都会增加(通过-O3)。
我相信这样做的原因是编译器正在为_objectCounter 成员变量分配空间,因此如果其他代码需要获取指向ObjectCounter 的指针,则可以提供唯一地址。但是我的程序中的任何代码实际上都没有引用_objectCounter 变量;它的存在只是为了在适当的时候执行自己的默认构造函数和析构函数。
鉴于此,有没有办法鼓励(或者更好的是,强制)编译器不要为这个成员变量分配任何空间?
【问题讨论】:
-
尝试让
int64_t类成员成为该类的第一个成员。 -
@SamVarshavchik 我试过了,
sizeof(SomeUserClass)还是 16。 -
从
ObjectCounter继承,以便可以应用空基优化。在大多数情况下,它会。 -
切向:将
_objectCount从全局变量更改为属于ObjectCounter的静态类变量就足够简单了。简单但需要更多输入是通过添加复制和移动构造函数来更改它以遵守 3/5/0 规则,这些构造函数也会酌情增加计数器。 -
如果你使用的是 C++20 那么属性
[[no_unique_address]]