将结构化数据投影到std::向量的最有效方法是什么

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

本文关键字:有效 方法 是什么 向量 数据 投影 std 结构化      更新时间:2023-10-16

假设我有以下结构类型:

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 s和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_structYStruct 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;

vstd::vector,需要双重间接,因为矢量包含指向数据所在位置的指针。在少数情况下,我被迫明确使用以下方法:

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

相反,这释放了寄存器,并显著加快了执行速度,因为编译后的代码总是假设向量可以在循环期间重新分配,从而在每次迭代中重新执行两个间接步骤,即使重新分配在技术上是不可能的(根本没有调用外部代码,只是整数之间的简单操作,所有内容都是内联的)。