2012-11-04 28 views
7

考虑以下几点:我可以投出浮动浮动*的POD数组吗?

#include <vector> 
using namespace std; 

struct Vec2 
{ 
    float m_x; 
    float m_y; 
}; 

vector<Vec2> myArray; 

int main() 
{ 
    myArray.resize(100); 

    for (int i = 0; i < 100; ++i) 
    { 
    myArray[i].m_x = (float)(i); 
    myArray[i].m_y = (float)(i); 
    } 

    float* raw; 
    raw = reinterpret_cast<float*>(&(myArray[0])); 
} 

raw保证有正确的值200辆连续花车?也就是说,标准是否保证了这一点?

编辑:如果以上是有保证的,并且如果Vec2有一些功能(非虚拟)和一个构造函数,那么保证仍然存在吗?

注:我意识到这是危险的,在我的具体情况我没有 的选择,因为我有一个第三方库的工作。

+0

一个很好的问题,如果一切正常,就不会'飘*原料=(myarray的[0] .m_x) '没有铸造就做同样的事情? – Axel

回答

5

我意识到这是危险的,在我的特殊情况下,我别无选择因为我正在与第三方图书馆合作。

您可以添加编译结构尺寸的时间检查:

live demo

struct Vec2 
{ 
    float a; 
    float b; 
}; 

int main() 
{ 
     int assert_s[ sizeof(Vec2) == 2*sizeof(float) ? 1 : -1 ]; 
} 

它会增加你的你的方法的信心(这仍然是不安全的,由于reinterpret_cast的,如前所述)。


原始=的reinterpret_cast(&(myArray的[0]));

ISO C++ 98 9.2/17:

指向一个POD结构对象,使用的reinterpret_cast,点到它的初始构件适当地转换(或如果该构件是一个位域,然后到它所在的单位),反之亦然。 [注意:因此在标准布局结构对象中可能存在未命名的填充,但在开始时并不需要填充,以实现适当的对齐。末端注]


最后,对应地址的运行时检查会做出这样的解决方案,而安全。它可以在单元测试期间或甚至在程序的每个开始(在小测试阵列上)完成。

全部放在一起:

live demo

#include <vector> 
#include <cassert> 
using namespace std; 
struct Vec2 
{ 
    float a; 
    float b; 
}; 

int main() 
{ 
    int assert_s[ sizeof(Vec2) == 2*sizeof(float) ? 1 : -1 ]; 
    typedef vector<Vec2> Vector; 
    Vector v(32); 
    float *first=static_cast<float*>(static_cast<void*>(&v[0])); 
    for(Vector::size_type i,size=v.size();i!=size;++i) 
    { 
     assert((first+i*2) == (&(v[i].a))); 
     assert((first+i*2+1) == (&(v[i].b))); 
    } 
    assert(false != false); 
} 
+1

C++ 11有'static_assert',它更适合这个目的。 –

+0

我知道这一点。还有BOOST_STATIC_ASSERT。但是上面的代码可以在C++ 98编译器上工作,不需要额外的库。 –

+1

鼓励采用C++ 11通过炫耀很酷的功能:) –

-1

的唯一保证一个reinterpret_cast给的,你得到的原始对象时,你reinterpret_cast铸造对象回原始数据类型。

尤其是,raw不保证有200个连续的浮点数和正确的值。

+1

这是旁白。 –

+0

这完全是关键。 – Oswald

+1

不,我不这么认为。正如Axel所评论的那样,这个例子可以通过'float * raw =&(myArray [0] .m_x)'给出。 'reinterpret_cast'是无关紧要的。 –

3

不,这是不安全的,因为编译器可以在结构中的两个float之间或之后自由插入填充,因此结构中的float可能不是连续的。

如果你仍然想尝试一下,你可以添加编译时检查,以增加更多的保证,这将工作:

static_assert(sizeof(Vec2) == sizeof(float) * 2, "Vec2 struct is too big!"); 
static_assert(offsetof(Vec2, b) == sizeof(float), "Vec2::b at the wrong offset!"); 
+0

恕我直言,第二次检查(offsetof)在第一次之后不需要。 POD结构成员在内存中具有缓存顺序。 –