Допустим, у меня есть следующие типы структур:
struct XStruct {
int a_value;
int b_value;
}
struct YStruct {
int c_value;
int d_value;
};
Теперь у меня есть следующий вектор:
std::vector<XStruct> m_x_values;
И я хочу проецировать свои данные так, чтобы c_value
s = b_value
с и d_value
s = a_value
s
std::vector<YStruct> m_y_values;
Какой самый эффективный способ сделать это:
Опция 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});
}
Вариант 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;
}
Любое другое предложение?
Вы можете создать конструктор второй структуры следующим образом:
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;
};
Вы сможете использовать y_struct = x_struct
или же YStruct y_struct(x_struct)
,
Затем просто скопируйте каждый элемент первого вектора во второй.
алгоритм STL transform
подходит для такого рода проблем.
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 };
});
Или использовать vector::emplace_back
сохранить немного YStruct
время построения, но это займет некоторое время, когда вектор будет изменен.
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
может быть инициализирован с помощью пары итераторов, и это позволяет использовать эту идиому:
std::vector<A> new_vect(old_vect.begin(), old_vect.end());
таким образом, определяя конструктор для Y
принимая const X&
в качестве параметра вы будете выражать свое намерение настолько четко и кратко, насколько это возможно, предоставляя библиотеке свободу делать все, что лучше для выполнения операции.
Делегирование в библиотеку и надежда на то, что она делает все возможное, — это не стратегия, которая всегда побеждает (на самом деле вовсе), а в случае std::vector
Я был бы достаточно уверен, что разработчики компилятора сделали все возможное, чтобы выполнить операцию как можно быстрее.
Если есть сомнения (и только если вы на самом деле измеренный эта операция является узким местом для вашего кода, и это не просто догадки), затем попробуйте измерить другие подходы и даже, возможно, проверить сгенерированный машинный код. Это не должно происходить часто.
Для моего опыта я бы ожидал reserve
+ push_back
Версия худший подход с точки зрения производительности, потому что компиляторы сегодня не достаточно умны (AFAIK), чтобы обнаружить этот паттерн. Даже назначение каждого элемента может быть не самым быстрым способом, потому что когда вы пишете
v[i] = x;
а также v
является std::vector
двойная косвенность необходима, потому что вектор содержит указатель на то, где находятся данные. В некоторых случаях я был вынужден явно использовать подход:
X* vp = &v[0];
for (int i=0,n=v.size(); i<n; i++) {
vp[i] = ...
}
вместо этого это высвободило регистры и значительно ускорило выполнение, потому что в противном случае скомпилированный код всегда предполагал, что вектор мог быть перераспределен во время цикла, таким образом, повторяя два шага косвенности на каждой итерации, даже если перераспределение было технически невозможно (нет внешнего кода вызывается вообще, просто простые операции между целыми числами, все встроено).