代码之家  ›  专栏  ›  技术社区  ›  Jeremy Friesner

是否可以在不增加包含对象大小的情况下添加私有成员变量?

  •  2
  • Jeremy Friesner  · 技术社区  · 5 年前

    我有一个小小的实用程序类,叫做 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 成员变量:

    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 变量它的存在只是为了在适当的时候执行自己的默认构造函数和析构函数。

    考虑到这一点,有没有办法鼓励(或者更好的是,强制)编译器不为该成员变量分配任何空间?

    1 回复  |  直到 5 年前
        1
  •  5
  •   NathanOliver    5 年前

    如果可以使用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