我的 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)
我有以下 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)