简体   繁体   中英

What is the most efficient way to project structured data to a std::vector?

Let's say I have the following struct types:

struct XStruct {
   int a_value;
   int b_value;
}

struct YStruct {
   int c_value;
   int d_value;
};

Now I have the following vector:

std::vector<XStruct> m_x_values;

And I want to project my data to so that c_value s = b_value s and d_value s = a_value s

std::vector<YStruct> m_y_values;

What's the most efficient way to do this:

Option 1:

m_y_values.clear();
m_y_values.reserve(m_x_values.size());

for(auto x : m_x_values)
{
    m_y_values.push_back({x.b_value, x.a_value});
}

Option 2:

m_y_values.resize(m_x_values.size());
int i = 0;
for(auto x : m_x_values)
{
    m_y_values[i].c_value = x.b_value
    m_y_values[i].d_value = x.a_value;
    ++i;
}

Any other suggestion?

You can create constructor of the second struct like that:

struct YStruct {
   explicit YStruct(const &XStruct x_struct)
   : c_value(x_struct.a_value)
   , d_value(x_struct.b_value)
   {};

   int c_value;
   int d_value;
};

You will be able to use y_struct = x_struct or YStruct y_struct(x_struct) . Then simple copy each element of first vector to second.

the STL algorithm transform is suitable for this kind of problems.

std::vector<XStruct> x_values = { { 1, 2 }, {3, 4} };
std::vector<YStruct> y_values(x_values.size());

std::transform(x_values.begin(), x_values.end(), y_values.begin(), [](const XStruct& x){
    return YStruct{ x.b_value, x.a_value };
});

Or use vector::emplace_back to save some YStruct construction time, but it will take some time when the vector is being resized.

std::vector<XStruct> x_values = { { 1, 2 }, {3, 4} };
std::vector<YStruct> y_values;

for (const auto& x : x_values){
    y_values.emplace_back(YStruct{ x.b_value, x.a_value });
}

std::vector can be initialized using a pair of iterators and this allows using this idiom:

std::vector<A> new_vect(old_vect.begin(), old_vect.end());

thus by defining a constructor for Y accepting a const X& as parameter you would be expressing your intention as clearly and concisely as possible, leaving to the library the freedom to do whatever is best to do the operation.

Delegating to a library and hoping that it's doing the best is not a strategy that always wins (not at all, actually) but in case of std::vector I'd be reasonably confident that the compiler implementers did all they could to get the operation as fast as possible.

When in doubt (and only if you actually measured this operation is a bottleneck for your code and it's not just guessing) then try measuring other approaches and even possibly inspect the machine code generated. It shouldn't be something happening often.

For my experience I'd expect a reserve + push_back version the worst approach from a performance point of view because compilers today are not smart enough (AFAIK) to detect this pattern. Even assigning each element may be not the fastest way because when you write

v[i] = x;

and v is an std::vector a double indirection is needed because a vector contains a pointer to where the data is. In a few cases I've been forced to explicitly use the approach:

X* vp = &v[0];
for (int i=0,n=v.size(); i<n; i++) {
    vp[i] = ...
}

instead and this freed up registers and speeded up execution measurably because the compiled code was otherwise always assuming that the vector could have been reallocated during the loop thus redoing the two indirection steps at each iteration, even if a reallocation was technically impossible (no external code called at all, just simple operations between integers, everything inlined).

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.

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