preventing堆未对齐的数据 [英] preventing unaligned data on the heap

查看:196
本文介绍了preventing堆未对齐的数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我建立一个使用上证所内部函数功能,而一些类的成员必须是16字节对齐的类层次结构。对于栈实例,我可以使用 __ declspec(对齐(#)),像这样:

I am building a class hierarchy that uses SSE intrinsics functions and thus some of the members of the class need to be 16-byte aligned. For stack instances I can use __declspec(align(#)), like so:

typedef __declspec(align(16)) float Vector[4];
class MyClass{
...
private:
Vector v;
};

现在,因为 __ declspec(对齐(#))是一个编译指令,下面code,可能会导致矢量在堆上未对齐的实例:

Now, since __declspec(align(#)) is a compilation directive, the following code may result in an unaligned instance of Vector on the heap:

MyClass *myclass = new MyClass;

这太,我知道我可以很容易地通过重载解决的删除的运营商使用 _aligned_malloc _aligned_free 相应。像这样:

This too, I know I can easily solve by overloading the new and delete operators to use _aligned_malloc and _aligned_free accordingly. Like so:

//inside MyClass:
public:
void* operator new (size_t size) throw (std::bad_alloc){
    void * p = _aligned_malloc(size, 16);
    if (p == 0)  throw std::bad_alloc()
    return p; 
}

void operator delete (void *p){
    MyClass* pc = static_cast<MyClass*>(p); 
    _aligned_free(p);
}
...

到目前为止好..但这里是我的问题。请看下面的code:

So far so good.. but here is my problem. Consider the following code:

class NotMyClass{ //Not my code, which I have little or no influence over
...
MyClass myclass;
...
};
int main(){
    ...
    NotMyClass *nmc = new NotMyClass;
    ...
}

由于 MyClass的的静态创建于NotMyClass的动态实例的MyClass的实例,MyClass的将是16个字节的比较一致的,因为Vector的 __ declspec(对齐(16))指令。但是,这是不值钱的,因为NMC是动态分配在堆上与NotMyClass的的运营商,它不nesessarily保证(绝对可能不是)16字节对齐。

Since the myclass instance of MyClass is created statically on a dynamic instance of NotMyClass, myclass WILL be 16-byte aligned relatively to the beginning of nmc because of Vector's __declspec(align(16)) directive. But this is worthless, since nmc is dynamically allocated on the heap with NotMyClass's new operator, which doesn't nesessarily ensure (and definitely probably NOT) 16-byte alignment.

到目前为止,我只能想办法2对如何处理这个问题:

So far, I can only think of 2 approaches on how to deal with this problem:

  1. preventing MyClass的从能够编译以下code用户:

  1. Preventing MyClass users from being able to compile the following code:

MyClass myclass;

意义,只能动态创建的MyClass实例,采用了新的运营商,从而确保MyClass的所有实例是真正的动态allocatted与MyClass的的重载新。我咨询关于如何做到这一点另一个线程,并得到了一些伟大的答案: <一href="http://stackoverflow.com/questions/3092198/c-$p$pventing-class-instance-from-being-created-on-the-stack-during-compiltaio">C++,从栈上创建(compiltaion期间)

meaning, instances of MyClass can only be created dynamically, using the new operator, thus ensuring that all instances of MyClass are truly dynamically allocatted with MyClass's overloaded new. I have consulted on another thread on how to accomplish this and got a few great answers: C++, preventing class instance from being created on the stack (during compiltaion)

还原,只有具有指针向量作为成员,我会分配和释放使用 _aligned_malloc _aligned_free 的构造函数和析构函数。这methos显得粗糙,容易出错,因为我不是唯一的程序员写这些类(MyClass的派生自一个基类,许多这些类的使用SSE)。

Revert from having Vector members in my Class and only have pointers to Vector as members, which I will allocate and deallocate using _aligned_malloc and _aligned_free in the ctor and dtor respectively. This methos seems crude and prone to error, since I am not the only programmer writing these Classes (MyClass derives from a Base class and many of these classes use SSE).

不过,由于这两种解决方案都在我的球队遭人白眼,我来给你一个不同的解决方案建议。

However, since both solutions have been frowned upon in my team, I come to you for suggestions of a different solution.

推荐答案

如果您对堆分配设置,另一个想法是在分配堆栈上,并手动对齐(手动校正在<一个讨论href="http://stackoverflow.com/questions/227897/solve-the-memory-alignment-in-c-interview-question-that-stumped-me/227900#227900">this SO帖子)。我们的想法是分配字节数据(无符号的字符),其尺寸保证包含必要的大小( +15 ),然后找到对准位置由从最移区域舍去( X + 15 - (X + 15)%16 X + 15安培;〜为0x0F )。我张贴与向量运算这种方法在 codePAD (的工作示例 G ++ -O2 -msse2 )。这里是重要的位:

If you're set against heap allocation, another idea is to over allocate on the stack and manually align (manual alignment is discussed in this SO post). The idea is to allocate byte data (unsigned char) with a size guaranteed to contain an aligned region of the necessary size (+15), then find the aligned position by rounding down from the most-shifted region (x+15 - (x+15) % 16, or x+15 & ~0x0F). I posted a working example of this approach with vector operations on codepad (for g++ -O2 -msse2). Here are the important bits:

class MyClass{
   ...
   unsigned char dPtr[sizeof(float)*4+15]; //over-allocated data
   float* vPtr;                            //float ptr to be aligned

   public:
      MyClass(void) : 
         vPtr( reinterpret_cast<float*>( 
            (reinterpret_cast<uintptr_t>(dPtr)+15) & ~ 0x0F
         ) ) 
      {}
   ...
};
...

构造可确保vptr的对齐(注意成员在类声明的顺序很重要)。

The constructor ensures that vPtr is aligned (note the order of members in the class declaration is important).

此方法适用(堆/堆栈包含类的配置是无关对齐),是portabl上下的(我想大多数编译器提供一个指向大小UINT uintptr_t形式),并不会造成内存泄漏。但它不是特别安全(即一定要保持对准指针下副本有效,等等),废物(近)的内存,因为它使用,有的可能会发现reinter pret_casts反感。

This approach works (heap/stack allocation of containing classes is irrelevant to alignment), is portabl-ish (I think most compilers provide a pointer sized uint uintptr_t), and will not leak memory. But its not particularly safe (being sure to keep the aligned pointer valid under copy, etc), wastes (nearly) as much memory as it uses, and some may find the reinterpret_casts distasteful.

对齐操作的风险/未对齐数据的问题,可以主要是由在Vector对象封装这样的逻辑,从而控制进入对齐的指针,并确保它被在施工对齐和保持有效消除。

The risks of aligned operation/unaligned data problems could be mostly eliminated by encapsulating this logic in a Vector object, thereby controlling access to the aligned pointer and ensuring that it gets aligned at construction and stays valid.

这篇关于preventing堆未对齐的数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆