I've a vector of pair which I need to copy them linearly to a vector of ints. I've the following code which works well, but I'm not sure if it's safe considering struct padding issues in 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());
Now, my question is - Is the above code safe? If not, is there an elegant way to do it without writing a loop?
How about std::transform
and a lambda function ?
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 ;});
If you can't use C++11, and probably "hate" doing linear copying using loops
You can use functor like:
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<<" ";
A reinterpret_cast
is usually bad news. Wouldn't you be better off reserve()ing enough space in the destination vector and then calling std::for_each
on the source vector of pairs and then have the function/lambda push_back both first and second into the destination vector ?
You're right to be concerned about structure padding issues, but I think you haven't really faced the central assumption that your code is making:
Can I treat a
std::pair<int, int>
as an array of two integers, with the.first
being the first element in the array and.second
being the second element?
From a "correctness" point of view, I'd say "no". You've identified padding issues, but there's also the ordering of the fields. There's really no guarantee that .first
has a lower memory address than .second
.
From a "practical" point of view, I'd be quite surprised your that code did not work. [ Edit: Neil has pointed out a concrete example where there are padding issues; so color me surprised. Besides being "bad form", I now consider the code broken in practice. ]
As for a solution, you can use for_each
with a custom action that pushes both elements of the pair (untested code)
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));
You don't need any fanciness for this problem. A simple for loop will do, especially if you can't use 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);
}
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.