简体   繁体   中英

Cast std::vector as another std::vector

I need to convert vector of triangles to thrice longer vector of indices:

struct Triangle { int16_t v[3] };

std::vector<Triangle>
std::vector<int16_t>

Maybe I can somehow convert iterators of an already-initialized vector from the raw memory it encapsulates?

EDIT: that is true, i don't want any copies.

You cannot do that.

However you can do this:

std::vector<Triangle> ts;
__int16 *pvbegin = ts[0].v;
__int16 *pvend = pvbegin + 3 * ts.size();

And use the pair pvbegin and pvend as an iterator range.

I'm not positively sure that it is not a technical Undefined Behavior, but it should work fine. To be sure it is a good idea to add a static_assert somewhere such as:

static_assert(sizeof(Triangle) == 3*sizeof(int16_t), "Weird sizeof(Triangle)");

Are you looking for a smart way, or just a way that works?

std::vector<int16_t> vec_int;
std::vector<Triangle> vec_tri;
for (const auto& tri : vec_tri)
{
    for (int i = 0; i < 3; i++)
    {
        vec_int.push_back(tri.v[i]);
    }
}

BIG EDIT: This seems to be correct and easy (all tested)

static_assert(sizeof(Triangle) == 3*sizeof(int16_t),
    "Weird sizeof(Triangle)");
struct SimpleWrapper {
private:
    std::vector<Triangle>& vect;
public:
    SimpleWrapper(std::vector<Triangle>& vect)
    : vect(vect) {
    }
    int16_t* begin() {
        return vect[0].v;
    }
    int16_t* end() {
        return begin() + vect.size()*3;
    }
};

ORIGINAL:

#include <vector>
#include <iostream>

struct Triangle { int16_t v[3]; };

struct Iterator: std::iterator<
  std::input_iterator_tag,
  int16_t> {
private:
    std::vector<Triangle>& vect;
    int index, subidx;
public:
    Iterator(
      std::vector<Triangle>& vect,
      int index, int subidx)
    : vect(vect), index(index), subidx(subidx) {
    }
    Iterator(const Iterator& src)
    : vect(src.vect), index(src.index), subidx(src.subidx) {
    }
    Iterator& operator++() {
        if(++subidx == 3) {
            subidx = 0; index++;
        }
        return *this;
    }
    Iterator operator++(int) {
        Iterator tmp(*this);
        operator++();
        return tmp;
    }
    bool operator==(const Iterator& rhs) {
        return &rhs.vect == &vect
          && rhs.index == index
          && rhs.subidx == subidx;
    }
    bool operator!=(const Iterator& rhs) {
        return !(*this == rhs);
    }
    int16_t& operator*() {
        return vect[index].v[subidx];
    }
};

struct Wrapper {
private:
    std::vector<Triangle>& vect;
public:
    Wrapper(std::vector<Triangle>& vect)
    : vect(vect) {
    }
    Iterator begin() {
        return Iterator(vect, 0, 0);
    }
    Iterator end() {
        return Iterator(vect, vect.size(), 0);
    }
};

int main() {
    std::vector<Triangle> vect;
    vect.push_back(Triangle { 1,2,3 });
    vect.push_back(Triangle { 6,7,8 });

    Wrapper wrap(vect);
    for (int16_t v : wrap)
        std::cout << v << ' ';
}

Definitely not, since accessing the vector's 'length' will almost certainly be wrong. There may be other opaque implementation details that will be wrong too. At best you might be able to cast:

#include <type_traits>
...
static_assert(sizeof(Triangle) == (sizeof(int16_t) * 3) &&
              std::is_standard_layout<Triangle>::value),
              "Triangle does not satisfy contiguous storage requirements");

// i-th triangle from: std::vector<int16_t> values
Triangle *t = reinterpret_cast<Triangle *>(& values[i * 3]);

The standard doesn't make many guarantees about reinterpret_cast .

If you only really care about how you access the data, rather than literally whether it is stored in a std::vector<int16_t> , you could make your own iterator to iterate over the vertices in sequence. If the iterator is currently at the first vertex of a triangle, incrementing it would bring you to the second vertex; from the second vertex, incrementing would bring you to the third vertex; and from the third vertex, incrementing would give you the first vertex of the next triangle.

You could also make an object that provided "random access" to the vertices of the triangles, taking as input a number from 0 to number_of_triangles-1, inclusive.

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