将一个 pair<int,int> 类型的向量复制到一个 int 类型的向量中(C++)

4

我有一个pair向量,需要线性地将它们复制到一个int向量中。我有以下代码可以正常工作,但我不确定在考虑C ++中的结构填充问题时是否安全。

std::vector < std::pair<int, int> > test_vector;
for (int i=0;i<5;i++) {
    test_vector.push_back(std::make_pair(i,i*5));
}
std::vector<int> int_vec(test_vector.size() * 2);
std::copy(reinterpret_cast<int*>(&(*test_vector.begin())),reinterpret_cast<int*>(&(*test_vector.end())),int_vec.begin());

现在,我的问题是 - 上面的代码安全吗?如果不安全,有没有一种优雅的方法可以做到不用编写循环呢?

这比写循环更优雅吗?只是问问而已。 - john
我想你在技术上可以从调用std::accumulate返回结果向量,而且算法名称在某种程度上也有意义。 - chris
想想看,只需要两行代码。如果我使用back_inserter而不是预先分配,那么实际上只需要一行代码。使用现有的STL算法编写单行代码总是比编写容易出错的循环更加优雅(这是我的观点)。尤其是当它是另一个例程的一部分时。 - rwb
4个回答

5
如何使用 std::transform 和 lambda 函数?
std::vector<int> v;
std::transform(test_vector.begin(), test_vector.end(), std::back_inserter(v), 
               [&v](const std::pair<int, int> &p) 
               { v.push_back( p.first);
                 return p.second ;});

如果您无法使用C++11,并且可能“讨厌”使用循环进行线性复制,您可以使用类似于函数的对象(functor):
struct X{
    X(std::vector<int> &x) :v(x){}
    int operator () (const std::pair<int, int> &p)
    {
        v.push_back(p.first);
        return p.second;
    }
    std::vector<int> &v;
};

std::vector<int> v; //Final vector

std::transform(test_vector.begin(), 
               test_vector.end(), 
               std::back_inserter(v), 
               X(v));

std::vector<int> ::iterator it;

for(it=v.begin() ; it!=v.end() ;++it)
  std::cout<<*it<<" ";

谢谢!不幸的是我还没有使用C++11 (VS2008)。但是我可以使用Boost。你能否使用Boost写一个呢? - rwb
2
@rwb 你可以编写一个函数对象类来在旧版C++中使用。 - Neil Kirk
是的,我当然可以编写一个函数对象。但我只是想知道是否有其他方法,即使这意味着使用 Boost。 - rwb

1
您对结构填充问题的担忧是正确的,但我认为您尚未真正面对您的代码所做的中心假设:

我能将std::pair<int, int>视为由两个整数组成的数组,其中.first是数组中的第一个元素,.second是第二个元素吗?

从"正确性"角度来看,我会说"不行"。您已经发现了填充问题,但字段的顺序也很重要。实际上,并没有保证.first具有比.second更低的内存地址。

从"实用"角度来看,如果您的代码无法工作,我会感到非常惊讶。 [编辑:Neil指出了一个具体的例子,存在填充问题;所以我很惊讶。除了"不好的形式"之外,我现在认为这段代码已经崩溃了。]

至于解决方案,您可以使用具有自定义操作的for_each来推送一对的两个元素(未经测试的代码)。
struct action {
    action ( vector<int> & target ) : t_(target) {}
    void operator () ( const pair &p ) const 
        { t_.push_back(p.first); t_.push_back(p.second); }
private:
    vector<int> &t_;
}

for_each ( test_vector.begin(), test_vector.end(), action(v));

-9999999999999999 表示这在实际中可以接受。 - Neil Kirk
抱歉,如果我给你那样的印象;我的意图是说代码实际上可以完成OP想要做的事情 - 并不是说这是个好主意。 - Marshall Clow
除非由于填充问题而不行。 - Neil Kirk
好的。你有没有一个填充问题导致它失败的例子? - Marshall Clow
整数类型 int 是 32 位的,结构体会被填充到 64 位。 - Neil Kirk
显示剩余2条评论

1
你不需要任何花哨的东西来解决这个问题。一个简单的for循环就可以了,特别是如果你不能使用C++11。
std::vector < std::pair<int, int> > test_vector;
std::vector<int> int_vec; int_vec.reserve(test_vector.size() * 2);
for (std::vector < std::pair<int, int> >::const_iterator it = test_vector.begin(), end_it = test_vector.end(); it != end_it; ++it)
{
    int_vec.push_back(it->first);
    int_vec.push_back(it->second);
}

循环是简单的,使用其他任何东西可能会过度设计,但我很好奇是否可以使用STL算法。 - rwb

1

reinterpret_cast 通常是个坏消息。你最好在目标向量中 reserve() 足够的空间,然后对源 pair 向量调用 std::for_each,并让函数/lambda将 first 和 second 都 push_back 到目标向量中。


有趣。不幸的是,我对lambda的了解非常有限。是否有一种方法可以在不使用函数对象的情况下一次将第一个和第二个元素都push_back进去?我仍然使用C++03标准,但我可以使用Boost作为替代方案。 - rwb
我想不出一种在一个调用中完成它的方法,除非使用类似于你已经拥有的东西。函数对象是我能想到的最安全/最可移植的方式。 - Duncan Smith

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接