有以下代码段错误的明显原因吗?
#include <vector>
#include <emmintrin.h>
struct point {
__m128i v;
point() {
v = _mm_setr_epi32(0, 0, 0, 0);
}
};
int main(int argc, char *argv[])
{
std::vector<point> a(3);
}
由于
编辑:我在linux / i686上使用g ++ 4.5.0,我可能不知道我在做什么,但是因为即使是以下的段错误
int main(int argc, char *argv[])
{
point *p = new point();
}
我真的认为必须和对齐问题。
答案 0 :(得分:11)
如果v
未正确对齐,可能出错的显而易见的事情就是。
但它是由vector
动态分配的,所以它不受堆栈错位问题的影响。
但是,正如phooji正确指出的那样,“模板”或“原型”值将传递给std::vector
构造函数,该构造函数将被复制到向量的所有元素。 <{1}}的这个参数将被放置在堆栈上并且可能未对齐。
有些编译器有一个用于控制函数内堆栈对齐的编译指示(基本上,编译器会根据需要浪费一些额外的空间来使所有本地正确对齐)。
根据Microsoft文档Visual C++ 2010 should set up 8 byte stack alignment automatically for SSE types和has done so since Visual C++ 2003
对于gcc,我不知道。
在C ++ 0x下,std::vector::vector
返回未对齐存储是一种严重的违规行为。 new point()
说(来自n3225草案的措辞):
分配功能尝试分配所请求的存储量。如果成功,它应该 返回存储块的起始地址,其长度以字节为单位应至少与 要求的大小。返回时,分配的存储内容没有限制 分配功能。连续调用分配的存储的顺序,连续性和初始值 分配功能未指定。返回的指针应适当对齐,以便可以转换 到具有基本对齐要求(3.11)的任何完整对象类型的指针然后使用 访问分配的存储中的对象或数组(直到通过调用显式释放存储 相应的解除分配函数)。
[basic.stc.dynamic.allocation]
说:
另外,请求运行时分配动态存储 请求的对齐不能被视为分配失败。
你可以尝试更新版本的gcc吗?
答案 1 :(得分:3)
您正在使用的vector
构造函数实际上是这样定义的:
explicit vector ( size_type n, const T& value= T(), const Allocator& = Allocator() );
(参见例如http://www.cplusplus.com/reference/stl/vector/vector/)。
换句话说,一个元素是默认构造的(即,当您调用构造函数时的默认参数值),然后通过复制第一个元素来创建其余元素。我的猜测是你需要point
的复制构造函数来正确处理__m128i
值的(非)复制。
更新:当我尝试使用Visual Studio 2010(v.10.0.30319.1)构建代码时,出现以下构建错误:
error C2719: '_Val': formal parameter with __declspec(align('16')) won't be aligned c:\program files\microsoft visual studio 10.0\vc\include\vector 870 1 meh
这表明Ben对于这种对齐问题是正确的。
答案 2 :(得分:1)
编译器的STL实现中的默认分配器分配的内存可能没有对齐。这将取决于特定平台和编译器供应商。
通常默认分配器使用运算符new
,它通常不保证超出字大小(32位或64位)的对齐。要解决此问题,可能需要实现使用_aligned_malloc
的自定义分配器。
另外,一个简单的修复(虽然不是一个令人满意的修复)是将值赋给本地__m128i
变量,然后使用未对齐的指令将该变量复制到结构。例如:
struct point {
__m128i v;
point() {
__m128i temp = _mm_setr_epi32(0, 0, 0, 0);
_mm_storeu_si128(&v, temp);
}
};
答案 3 :(得分:1)
SSE内在函数需要在内存中进行16字节对齐。在堆栈上分配__m128
时,没有问题,因为编译器会自动正确对齐这些问题。处理动态内存分配的std::vector<>
的默认分配器不会产生对齐的分配。