11

以下代码段错误是否有明显的原因?

#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();
}

我真的认为这一定是和对齐问题。

4

4 回答 4

11

v如果没有正确对齐,那么明显的可能出错的事情就是。

但它是由 动态分配的vector,因此不受堆栈错位问题的影响。

但是,正如phooji正确指出的那样,“模板”或“原型”值被传递给std::vector构造函数,该构造函数将被复制到向量的所有元素。正是这个参数std::vector::vector将被放置在堆栈上并且可能未对齐。

一些编译器具有用于控制函数内的堆栈对齐的编译指示(基本上,编译器会根据需要浪费一些额外的空间来使所有局部变量正确对齐)。

根据 Microsoft 文档,Visual C++ 2010 应该为 SSE 类型自动设置 8 字节堆栈对齐,并且自 Visual C++ 2003 以来已经这样做了

对于 gcc 我不知道。


在 C++0x 下,fornew point()返回未对齐的存储是严重的违规行为。 [basic.stc.dynamic.allocation]说(来自草案 n3225 的措辞):

分配函数尝试分配请求的存储量。如果成功,它将返回存储块的开始地址,其字节长度应至少与请求的大小一样大。从分配函数返回时分配的存储内容没有限制。连续调用分配函数分配的存储的顺序、连续性和初始值是未指定的。返回的指针应适当对齐,以便可以将其转换为具有基本对齐要求(3.11)的任何完整对象类型的指针,然后用于访问已分配存储中的对象或数组(直到存储被显式释放调用相应的释放函数)。

[basic.align]说:

此外,对于动态存储的运行时分配请求,其所请求的对齐不能被兑现,应被视为分配失败。

您可以尝试更新版本的 gcc 来解决这个问题吗?

于 2011-03-07T05:39:11.000 回答
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 在这方面是正确的,因为这是一个对齐问题。

于 2011-03-07T05:21:10.793 回答
1

编译器的 STL 实现中由默认分配器分配的内存可能未对齐。这将取决于特定的平台和编译器供应商。

通常默认分配器使用 operator 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);
    }
};
于 2011-03-07T05:26:43.547 回答
1

SSE 内在函数需要在内存中对齐 16 字节。当您__m128在堆栈上分配 an 时,没有问题,因为编译器会自动正确对齐它们。处理动态内存分配的默认分配器std::vector<>不会产生对齐的分配。

于 2011-03-07T05:39:01.443 回答