假设我有以下简单的结构:
struct Vector3
{
double x;
double y;
double z;
};
Run Code Online (Sandbox Code Playgroud)
我创建了一个顶点列表:
std::vector<Vector3> verticesList;
Run Code Online (Sandbox Code Playgroud)
除此之外,我还需要使用第三方库.该库具有以下签名的功能:
typedef double[3] Real3;
external void createMesh(const Real3* vertices, const size_t verticesCount);
Run Code Online (Sandbox Code Playgroud)
转换verticesList成可以createMesh()作为vertices参数传递的东西的最佳方法是什么?
目前我使用以下方法:
static const size_t MAX_VERTICES = 1024;
if (verticesList.size() > MAX_VERTICES)
throw std::exception("Number of vertices is too big");
Real3 rawVertices[MAX_VERTICES];
for (size_t vertexInd = 0; vertexInd < verticesList.size(); ++vertexInd)
{
const Vector3& vertex = verticesList[vertexInd];
rawVertices[vertexInd][0] = vertex.x;
rawVertices[vertexInd][1] = vertex.y;
rawVertices[vertexInd][2] = vertex.z;
}
createMesh(rawVertices, verticesList.size());
Run Code Online (Sandbox Code Playgroud)
但肯定不是解决问题的最佳方法.
这是一种正确的做法.还有其他一些方法......
类型Vector3是与类型兼容的布局Real3,这意味着您可以强制将指向一种类型的指针转换为另一种类型的指针:
createMesh( reinterpret_cast<Real3*>(&verticesList[0]), vertices.size() );
Run Code Online (Sandbox Code Playgroud)
正如Rook所提到的,其他替代方法是删除循环使用memcpy,因为类型是POD:
Real3 rawVertices[MAX_VERTICES];
std::memcpy( rawVertices, &verticesList[0],
vertices.size()*sizeof verticesList[0] );
Run Code Online (Sandbox Code Playgroud)
这更简洁,可能更有效,但它仍然是复制整个容器.
我相信标准确实保证了这种行为(至少是C++ 11),两种标准布局和标准兼容类型具有相同的内存布局(duh?)和§9.2p19状态:
指向标准布局结构对象的指针,使用reinterpret_cast进行适当转换,指向其初始成员(或者如果该成员是位字段,则指向它所在的单元),反之亦然.
这种保证在技术上意味着与我之前声称的略有不同:您可以reinterpret_cast<double*>(&verticesList[0])指出verticesList[0].x.但它也暗示通过重新解释演员转换double*为Real3指针也很好.