简体   繁体   中英

How to convert a stl vector of 3-element structs into 2D C-style array

Suppose I have the following simple struct:

struct Vector3
{
    double x;
    double y;
    double z;
};

and I create a list of vertices:

std::vector<Vector3> verticesList;

In addition to this I need to use a third-party library. The library has a function with the following signature:

typedef double[3] Real3;
external void createMesh(const Real3* vertices, const size_t verticesCount);

What is the best way to convert verticesList into something which could be passed into createMesh() as the vertices parameter?

At the moment I use the following approach:

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

But surely it is not the best way to solve the issue.

That is one proper way of doing it. There are also some other ways...

The type Vector3 is layout compatible with the type Real3 , the implication of this is that you can force casting a pointer to one type to a pointer of the other:

createMesh( reinterpret_cast<Real3*>(&verticesList[0]), vertices.size() );

Other alternative, as Rook mentions, to remove the loop is using memcpy , since the types are POD:

Real3 rawVertices[MAX_VERTICES];
std::memcpy( rawVertices, &verticesList[0], 
             vertices.size()*sizeof verticesList[0] );

This is more concise, and probably more efficient, but it still is copying the whole container.


I believe that the standard does guarantee this behavior (at least C++11), two standard layout and standard compatible types have the same memory layout (duh?), and §9.2p19 states:

A pointer to a standard-layout struct object, suitably converted using a reinterpret_cast, points to its initial member (or if that member is a bit-field, then to the unit in which it resides) and vice versa.

This guarantee technically means something slightly different than what I claimed before: you can reinterpret_cast<double*>(&verticesList[0]) points to verticesList[0].x . But it also implies that the conversion from double* to Real3 pointer through reinterpret cast will also be fine.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM