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

时间:2014-07-29 16:32:24

标签: c++ vector

我需要将三角形矢量转换为三倍较长的索引矢量:

struct Triangle { int16_t v[3] };

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

也许我可以以某种方式将已初始化的矢量的迭代器从它封装的原始内存中转换出来?

编辑:这是真的,我不想要任何副本。

5 个答案:

答案 0 :(得分:5)

你做不到。

但是你可以这样做:

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

并使用pvbeginpvend对作为迭代器范围。

我不确定它不是技术性的未定义行为,但它应该可以正常工作。确保在某处添加static_assert是个好主意,例如:

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

答案 1 :(得分:2)

您是在寻找一种聪明的方式,还是只是一种有效的方式?

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]);
    }
}

答案 2 :(得分:2)

BIG EDIT:这似乎是正确和容易的(所有测试)

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 << ' ';
}

答案 3 :(得分:1)

绝对不是,因为访问向量的“长度”几乎肯定是错误的。可能还有其他不透明的实现细节也是错误的。你最多也可以演员:

#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]);

该标准对reinterpret_cast没有多少保证。

答案 4 :(得分:0)

如果您只关心如何访问数据,而不是字面上是否存储在std::vector<int16_t>中,您可以使自己的迭代器按顺序迭代顶点。如果迭代器当前位于三角形的第一个顶点,则递增它会将您带到第二个顶点;从第二个顶点开始,递增会带你到第三个顶点;从第三个顶点开始,递增将为您提供下一个三角形的第一个顶点。

您还可以创建一个提供&#34;随机访问的对象&#34;到三角形的顶点,将一个从0到number_of_triangles-1的数字作为输入,包括在内。