我的 class 是否有更好的对象内存对齐方式?

Is there a better object memory alignment for my class?

我有以下 class,它的对齐方式是 8,大小是 40 字节(使用 gcc v11.2 64 位编译)。

class Foo
{
public:
    inline Foo( ) = default;
    /*
       other member functions such as
       move ctor and move assignment operator etc.
    */
    

private:
    mutable std::vector< std::vector<char> > _characterMatrix; // occupies 24 bytes on the stack
    int _Y_AxisLen; // 4 bytes
    int _X_AxisLen; // 4 bytes
    char _fillCharacter; // 1 byte

    inline static const std::unordered_set<char> CHAR_SET { '/', '\', '|', '-' }; // static member so nothing
};

并且这条语句:

std::cout << "Size: " << sizeof( Foo) << " --- alignment: " << alignof( Foo) << '\n';

生成这个: Size: 40 --- alignment: 8

class的大小实际上是8(size member of vector obj) + 8(capacity member of vector obj) + 8(qword pointer to the memory block on the heap for vector obj) + 4(整数)+ 4(整数)+ 1(字符)。所以 8+8+8+4+4+1 == 33 字节。并且每次初始化 Foo 实例时都会浪费 7 个字节。

所以我的问题是有没有办法将大小减小到 36?

我也试过这个:

class alignas( 4 ) Foo
{
public:
    inline Foo( ) = default;
    /*
       other member functions such as
       move ctor and move assignment operator etc.
    */
    

private:
    mutable std::vector< std::vector<char> > _characterMatrix;
    int _Y_AxisLen;
    int _X_AxisLen;
    char _fillCharacter;

    inline static const std::unordered_set<char> CHAR_SET { '/', '\', '|', '-' };
};

但是编译器忽略了 alignas(4)。尺码还是40

编辑:阅读一些评论后,我注意到在许多 STL 实现中,std::vector 对象没有指针、大小和容量成员,而是有 3 个指针(每个 8字节大小,所以总共也是 24 个字节)。

class Foo
    {
    public:
        inline Foo( ) = default;
        
    
    private:
        char **  _characterMatrix;  // 8 bytes
        int _Y_AxisLen; // 4 bytes
        int _X_AxisLen; // 4 bytes
        char _fillCharacter; // 1 byte
        intline static const std::unordered_set<char> CHAR_SET { '/', '\', '|', '-' };  
    };

您可以使用位域来精确控制成员的大小。

class Foo {
public:
    Foo() = default;
    ~Foo() = default;

    Foo(const Foo & other)
    : matrix(std::make_unique_for_overwrite<char[]>(other.size())), 
      Y_AxisLen(other.Y_AxisLen),
      X_AxisLen(other.X_AxisLen),
      FillCharacter(other.FillCharacter) {
        std::copy(other.matrix.get(), other.matrix.get() + size(), matrix.get());
    }
    Foo(Foo && other) = default;

    Foo& operator=(Foo other) {
        swap(matrix, other.matrix);
        Y_AxisLen = other.Y_AxisLen;
        X_AxisLen = other.X_AxisLen;
        FillCharacter = other.FillCharacter;
        return *this;
    }

private:
    static_assert(CHAR_BIT == 8, "Bit fields assume 8 bit char");

    std::size_t size() const { return Y_AxisLen * X_AxisLen; }

    // support [x][y] access
    char* operator[](size_t col) const { return matrix.get() + (col * Y_AxisLen); }

    std::unique_ptr<char[]> matrix;
    std::uint64_t Y_AxisLen : 28;
    std::uint64_t X_AxisLen : 28;
    std::uint64_t FillCharacter : 8;

    inline static const std::unordered_set<char> CHAR_SET { '/', '\', '|', '-' };
};

作为奖励,它有一个 size of 16(但仍然对齐 8)