Я строю иерархию классов, в которой используются встроенные функции SSE, и поэтому некоторые члены класса должны быть выровнены по 16 байтов. Для экземпляров стека я могу использовать __declspec(align(#))
, например:
typedef __declspec(align(16)) float Vector[4];
class MyClass{
...
private:
Vector v;
};
Теперь, поскольку __declspec(align(#))
является директивой компиляции, следующий код может привести к невыровненному экземпляру Vector в куче:
MyClass *myclass = new MyClass;
Это также, я знаю, я могу легко решить, перегрузив новые и delete операторы для использования _aligned_malloc
и _aligned_free
соответственно. Вот так:
//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);
}
...
Пока все хорошо ... но вот моя проблема. Рассмотрим следующий код:
class NotMyClass{ //Not my code, which I have little or no influence over
...
MyClass myclass;
...
};
int main(){
...
NotMyClass *nmc = new NotMyClass;
...
}
Поскольку экземпляр myclass MyClass
создается статически на динамическом экземпляре NotMyClass, myclass будет выровнен на 16 байт относительно начала nmc из-за директивы Vector __declspec(align(16))
. Но это бесполезно, поскольку nmc динамически выделяется в куче с помощью оператора new NotMyClass, который не обязательно (и, вероятно, вероятно, НЕ) 16-байтовое выравнивание.
Пока что я могу думать только о двух подходах к решению этой проблемы:
Запрет пользователям MyClass компилировать следующий код:
MyClass myclass;
Это означает, что экземпляры MyClass могут создаваться только динамически, с использованием оператора new, таким образом гарантируя, что все экземпляры MyClass действительно динамически распределяются с перегруженным новым MyClass. Я проконсультировался в другой ветке о том, как это сделать, и получил несколько отличных ответов:
C ++, предотвращение создания экземпляра класса в стеке (во время компиляции)
Отказаться от использования элементов Vector в моем классе и указателей на Vector только в качестве членов, которые я буду размещать и отменять, используя _aligned_malloc
и _aligned_free
в ctor и dtor соответственно. Этот метод кажется грубым и подверженным ошибкам, поскольку я не единственный программист, пишущий эти классы (MyClass является производным от базового класса, и многие из этих классов используют SSE).
Однако, поскольку оба решения были неодобрительны в моей команде, я прихожу к вам за предложениями другого решения.