C ++转换矢量类型到位

时间:2012-01-31 02:17:24

标签: c++ data-structures

是否可以在不创建新数据结构的情况下执行此操作? 假设我们有

struct Span{
    int from;
    int to;
}
vector<Span> s;

我们希望通过强制转换

直接从s得到一个整数向量
vector<Span> s;

vector<int> s;

所以我们可以删除/更改一些“from”,“to”元素,然后将其转换回

vector<Span> s;  

3 个答案:

答案 0 :(得分:2)

这不是一个好主意,但我会告诉你如何。

你可以通过这种方式得到一个指向整数的原始指针:

int * myPointer2 = (int*)&(s[0]);

但这实际上是不好的做法,因为你不能保证跨度结构没有任何padding,所以虽然它对我来说可能没什么用,但是今天我们对其他系统说不出多少

#include <iostream>
#include <vector>


struct Span{
    int from;
    int to;
};


int main()
{

    std::vector<Span> s;

    Span a = { 1, 2};
    Span b = {2, 9};
    Span c = {10, 14};

    s.push_back(a);
    s.push_back(b);
    s.push_back(c);


    int * myPointer = (int*)&(s[0]);

    for(int k = 0; k < 6; k++)
    {
        std::cout << myPointer[k] << std::endl;
    }

    return 0;
}

正如我所说,重新解释强制转换通常会起作用但非常危险,缺乏您通常期望从C / C ++中获得的跨平台保证。

接下来更糟糕的是,这实际上会按照你的要求行事,但你永远不应该这样做。这是你可以解雇的代码:

// Baaaad mojo here: turn a vector<span> into a vector<int>:
std::vector<int> * pis = (std::vector<int>*)&s;

for ( std::vector<int>::iterator It = pis->begin(); It != pis->end(); It++ )
        std::cout << *It << std::endl;

注意我是如何使用指向矢量的指针并指向矢量对象的地址。我希望两个载体的内部结构相同,我可以像这样使用它们。对我来说,这是有效的,虽然标准模板可能幸运地要求这样,但对于模板化的类通常不是这样(参见填充和模板特化)。

考虑复制数组(参见下面的参考文献2)或仅使用s 1。from和s [2] .to。

相关阅读:

  1. Are std::vector elements guaranteed to be contiguous?
  2. How to convert vector to array in C++

答案 1 :(得分:1)

免责声明:我绝对不知道关于你想要做什么。我只是在做出有根据的猜测,并在此基础上展示可能的解决方案。希望我能猜对了,你不必用愚蠢的演员做疯狂的诡计。

如果你想从矢量中删除某个元素,你需要做的就是找到它并使用the erase function删除它。您需要一个元素的迭代器,并获取该迭代器取决于您对所讨论元素的了解。鉴于std::vector<Span> v;

  • 如果你知道它的索引:

    v.erase(v.begin() + idx);
    
  • 如果您的对象与您正在寻找的对象相同:

    Span doppelganger;
    v.erase(std::find(v.begin(), v.end(), doppelganger));
    
  • 如果您的对象与您正在寻找的对象相同但想要删除所有相等的元素,则需要使用erase-remove惯用法:

    Span doppelganger;
    v.erase(std::remove(v.begin(), v.end(), doppelganger)),
            v.end());
    
  • 如果您有一些选择元素的标准:

    v.erase(std::find(v.begin(), v.end(),
                      [](Span const& s) { return s.from == 0; }));
    
    // in C++03 you need a separate function for the criterion
    bool starts_from_zero(Span const& s) { return s.from == 0; }
    
    v.erase(std::find(v.begin(), v.end(), starts_from_zero));
    
  • 如果您有一些标准,并且想要删除符合该标准的所有元素,则需要再次使用erase-remove惯用法:

    v.erase(std::remove_if(v.begin(), v.end(), starts_from_zero)),
            v.end());
    

答案 2 :(得分:1)

如果sizeof(Span) == sizeof(int) * 2(即Span没有填充),那么您可以安全地使用reinterpret_cast<int*>(&v[0])获取指向可以迭代的int数组的指针。您可以保证基于每个编译器的无填充结构,GCC中为__attribute__((__packed__)),Visual Studio中为#pragma pack

但是,有一种方法可以通过标准来保证。像这样定义Span

struct Span {
    int endpoints[2];
};

endpoints[0]endpoints[1] 必需是连续的。为方便起见,添加一些from()to()访问者,如果您愿意,但现在您可以使用reinterpret_cast<int*>(&v[0])内容。

但是如果你要做很多这样的指针修改,你可能想要制作自己的vector - 类似于这种处理方式的数据结构 - 提供更多安全保证的数据结构所以你可以避免出手。