问题描述
我有一个名为 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() 所报告的)。例如,以下代码显示当我包含 sizeof(SomeUserClass)
成员变量时,_objectCounter
在我的机器上从 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
变量;它的存在只是为了在适当的时候执行自己的默认构造函数和析构函数。
鉴于此,有没有办法鼓励(或者更好的是,强制)编译器不为该成员变量分配任何空间?
解决方法
如果您可以使用 C++20,则可以使用属性 [[no_unique_address]]
来完成此操作。使用
#include <cstdio>
#include <cstdint>
int _objectCount = 0; // global
class ObjectCounter
{
public:
ObjectCounter() {printf("DefaultCtor: count=%i\n",++_objectCount);}
~ObjectCounter() {printf("Dtor: count=%i\n",--_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)=%zu\n",sizeof(SomeUserClass));
printf("sizeof(ObjectCounter)=%zu\n",sizeof(ObjectCounter));
return 0;
}
输出:
DefaultCtor: count=1
sizeof(SomeUserClass)=8
sizeof(ObjectCounter)=1
Dtor: count=0