简体   繁体   English

将std :: vector转换为另一个std :: vector

[英]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. 并使用pvbeginpvend对作为迭代器范围。

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是一个好主意,例如:

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 . 该标准并未对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. 如果您只真正关心如何访问数据,而不是真正关心数据是否存储在std::vector<int16_t> ,则可以使自己的迭代器按顺序遍历顶点。 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. 您还可以制作一个对象,该对象提供对三角形顶点的“随机访问”,并输入从0到number_of_triangles-1(含)之间的数字。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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