对齐的成员变量和动态分配

Aligned member variables and dynamic allocation

本文关键字:动态分配 变量 成员 对齐      更新时间:2023-10-16

所以基本上,这就是我到目前为止得到的。 我有一个mat4类,它由__m128组成,需要在 16 字节边界上对齐:

_MM_ALIGN16
class mat4
{
   ...
};

我有另一个类,它本身没有对齐,但包含一个mat4.

class OtherClass
{
private:
   mat4 matrix;
   // Other data whose alignment doesn't really matter
   ...
};

我需要动态分配OtherClass的实例,ala:

OtherClass* stuff = new OtherClass[n];

如何保证实例内的mat4正确对齐,同时仍调用mat4 的构造函数?

我可以(并且通常更喜欢)使用 C++11 的功能,也许aligned_storage是我正在寻找的? 在这种情况下,我将如何使用它?

您可以使用放置 new 将内存分配与对象创建分离:

/* Memory allocation */
#ifdef _MSC_VER
     void *buffer = _aligned_malloc(n * sizeof(OtherClass), 16);
#else
     void *buffer = memalign(16, n * sizeof(OtherClass));
#endif
/* Object construction */
OtherClass *array = new (buffer) OtherClass[n];
/* Use your objects */
...
/* Object destruction */
for (size_t i = 0; i < n; i++) {
    array[i].~OtherClass();
}
/* Memory deallocation */
#ifdef _MSC_VER
     _aligned_free(buffer);
     buffer = nullptr;
#else
     free(buffer);
     buffer = nullptr;
#endif

一种更C++的方法是使用 std::vector 和一个对齐的分配器。

您可以使用 std::aligned_storage 来定义具有指定对齐方式的未初始化存储以及放置 new 运算符。

例如:

class OtherClass
{
private:
    using storage_t = typename std::aligned_storage<sizeof(mat4), 16>::type;
    storage_t _storage;
    mat4* address()  {
        return static_cast<mat4*>(static_cast<void*>(&_storage));
    }
    mat4 const* address() const {
        return static_cast<mat4 const*>(static_cast<void const*>(&_storage));
    }
public:
    OtherClass() { 
        new(address()) mat4();
    }
    OtherClass(OtherClass const& rhs) {
        new(address()) mat4(*rhs.address());
    }
    OtherClass& operator=(OtherClass const& rhs) {
        *address() = *rhs.address();
    }
    ~OtherClass() { 
       address()->~mat4(); 
    }  
    // setter
    template<typename... Args,
        class Enable = typename std::enable_if<
            std::is_constructible<mat4, Args...>::value
        >::type
    >
    void setMat(Args&&... args) {
        new(address()) mat4(std::forward<Args>(args) ...);
    }
    // getter
    mat4 const& getMat() const {
        return *address();
    }
    mat4& getMat() {
        return *address();
    }
    ...
};

另请参阅: 标准::aligned_storage

关于 SO 的类似问题:C++为对象分配存储而不初始化它?

union alignas (16) { __m128 _v; float _s[4]; }; -

例如,关于严格混叠的通常警告 - 不能保证堆存储对齐。

您可以通过查询 std::max_align_t 类型来避免新的/删除实现,如本答案中所述。

否则,可能需要重新实现全局运算符new/delete函数。我认为每类方法是不够的。例如,考虑具有mat4成员的类Camera;如果在堆栈上实例化了Camera,则应保留mat4成员对齐方式。如果在堆上创建了一个Camera对象,我看不出如何以其他方式强制执行。