是否可以在不增加包含对象的大小的情况下添加私有成员变量?
我有一个很小的实用程序类ObjectCounter,它没有虚方法和成员变量;它包含的只是一个构造函数和一个析构函数,它们分别增加和减少全局变量:
int _objectCount = 0; // global
class ObjectCounter
{
public:
ObjectCounter() {printf("DefaultCtor: count=%in", ++_objectCount);}
~ObjectCounter() {printf("Dtor: count=%in", --_objectCount);}
};
当我想跟踪我的程序在任何给定时间创建的另一个类的实例数时,我只需将一个ObjectCounter作为私有成员变量添加到该类中:
class SomeUserClass
{
public:
SomeUserClass() : _userData(0) {/* empty */}
~SomeUserClass() {/* empty */}
private:
ObjectCounter _objectCounter;
int64_t _userData;
};
(最初我会拥有该类的子类ObjectCounter,但是这样做会使我的 DOxygen 类图变得不必要地复杂,所以我将其更改为私有成员变量)
今天我注意到将这个“空”私有成员变量添加到我的类对象通常会增加类对象的大小(如 sizeof() 所报告的)。例如,以下代码显示sizeof(SomeUserClass)当我包含_objectCounter成员变量时,我的机器上从 8 增加到 16 :
int main(int, char **)
{
SomeUserClass sc1;
printf("sizeof(SomeUserClass)=%zun", sizeof(SomeUserClass));
printf("sizeof(ObjectCounter)=%zun", sizeof(ObjectCounter));
return 0;
}
无论是否启用优化(通过-O3),都会发生增加。
我相信这样做的原因是编译器只是为_objectCounter成员变量分配空间,以便如果其他代码需要获取指向 ObjectCounter 的指针,则可以提供唯一地址。但是我的程序中没有任何代码实际引用过该_objectCounter变量;它的存在仅仅是为了在适当的时候执行它自己的默认构造函数和析构函数。
鉴于此,有什么方法可以鼓励(或者更好的是强制)编译器不为该成员变量分配任何空间?
回答
如果您可以使用 C++20,则可以使用该属性[[no_unique_address]]来完成此操作。使用
#include <cstdio>
#include <cstdint>
int _objectCount = 0; // global
class ObjectCounter
{
public:
ObjectCounter() {printf("DefaultCtor: count=%in", ++_objectCount);}
~ObjectCounter() {printf("Dtor: count=%in", --_objectCount);}
};
class SomeUserClass
{
public:
SomeUserClass() : _userData(0) {/* empty */}
~SomeUserClass() {/* empty */}
private:
[[no_unique_address]] ObjectCounter _objectCounter;
int64_t _userData;
};
int main(int, char **)
{
SomeUserClass sc1;
printf("sizeof(SomeUserClass)=%zun", sizeof(SomeUserClass));
printf("sizeof(ObjectCounter)=%zun", sizeof(ObjectCounter));
return 0;
}
输出:
DefaultCtor: count=1
sizeof(SomeUserClass)=8
sizeof(ObjectCounter)=1
Dtor: count=0