只有在运行时才知道时,是否有一种有效的方法来初始化多维向量的大小?
Is there an efficient way to initialise the size of a multidimensional vector when only known at runtime?
我有一个 class,它有一个 3D 矢量作为它的变量之一。这个向量的大小直到运行时才知道。有没有一种有效的方法来初始化这个向量?
比如我的class可能是
class Foo {
public:
std::vector<std::vector<std::vector<float>>> x;
std::vector<std::vector<std::vector<float>>> y;
std::vector<std::vector<std::vector<float>>> z;
std::vector<std::vector<std::vector<float>>> bar;
int ni;
int nj;
int nk;
}
有构造函数
Foo::Foo(std::vector<std::vector<std::vector<float>>> x_,
std::vector<std::vector<std::vector<float>>> y_,
std::vector<std::vector<std::vector<float>>> z_) {
x = x_;
y = y_;
z = z_;
ni = x.size();
nj = x[0].size();
nk = x[0][0].size();
std::vector<std::vector<std::vector<float>>> tmp(ni, std::vector<std::vector<float>>(nj, std::vector<float>(nk)));
bar = tmp;
}
我可以执行上面的最后两行而不必分配虚拟变量 tmp
吗?
这就是你可以做到的(但不要错过阅读结尾):
#include <vector>
class Foo {
public:
std::vector<std::vector<std::vector<float>>> x;
std::vector<std::vector<std::vector<float>>> y;
std::vector<std::vector<std::vector<float>>> z;
int ni;
int nj;
int nk;
using inner_type = std::vector<float>;
using middle_type = std::vector<inner_type>;
using outer_type = std::vector<middle_type>;
outer_type bar;
Foo(outer_type x_,
outer_type y_,
outer_type z_) :
x(x_),y(y_),z(z_),
ni(x.size()),
nj(ni ? x[0].size() : 0),
nk(nj ? x[0].size() : 0),
bar( outer_type(ni,middle_type(nj,inner_type(nk))))
{
}
};
成员在构造函数主体执行之前被初始化,这就是我使用成员初始化列表的原因。而且我更改了成员的顺序,因为成员是按照它们在 class 定义中出现的顺序进行初始化的。访问 x[0]
让我有点紧张,所以我试图确保空向量不会造成破坏。
这行得通并且做你想做的(我希望),但是向量中填充了传递给它们的构造函数的临时对象的副本,这不是很有效。作为替代方案,您可以按照 .
中的建议调整成员大小
最后一点,如果你真的想要 std::vector<std::vector<std::vector<float>>>
,请重新考虑一下。如果您需要所有“行”具有相同数量的“列”,那么嵌套向量会让您为不使用的东西付费。此外,std::vector
最吸引人的特性是它的内存局部性。但是,std::vector<std::vector<float>>
中的 float
存储在内存的碎片区域中(因为元素没有直接存储在向量中)。
具有适当索引转换的平面 std::vector<float>
通常是更好的选择。
float& access_element(size_t i, size_t j, size_t k) {
return bar[ i *offset_i + j*offset_j + k];
}
您可以使用 resize()
和几个 for 循环来设置 bar
。它不是最漂亮的解决方案,但它应该具有相当不错的性能,因为不会创建临时对象并且没有不必要的分配。看起来像
bar.resize(ni);
for(auto& twodee : bar)
{
twodee.resize(nj);
for(auto& onedee : twodee)
onedee.resize(nk);
}
现在 bar
具有相同的大小并且用零填充。
我有一个 class,它有一个 3D 矢量作为它的变量之一。这个向量的大小直到运行时才知道。有没有一种有效的方法来初始化这个向量?
比如我的class可能是
class Foo {
public:
std::vector<std::vector<std::vector<float>>> x;
std::vector<std::vector<std::vector<float>>> y;
std::vector<std::vector<std::vector<float>>> z;
std::vector<std::vector<std::vector<float>>> bar;
int ni;
int nj;
int nk;
}
有构造函数
Foo::Foo(std::vector<std::vector<std::vector<float>>> x_,
std::vector<std::vector<std::vector<float>>> y_,
std::vector<std::vector<std::vector<float>>> z_) {
x = x_;
y = y_;
z = z_;
ni = x.size();
nj = x[0].size();
nk = x[0][0].size();
std::vector<std::vector<std::vector<float>>> tmp(ni, std::vector<std::vector<float>>(nj, std::vector<float>(nk)));
bar = tmp;
}
我可以执行上面的最后两行而不必分配虚拟变量 tmp
吗?
这就是你可以做到的(但不要错过阅读结尾):
#include <vector>
class Foo {
public:
std::vector<std::vector<std::vector<float>>> x;
std::vector<std::vector<std::vector<float>>> y;
std::vector<std::vector<std::vector<float>>> z;
int ni;
int nj;
int nk;
using inner_type = std::vector<float>;
using middle_type = std::vector<inner_type>;
using outer_type = std::vector<middle_type>;
outer_type bar;
Foo(outer_type x_,
outer_type y_,
outer_type z_) :
x(x_),y(y_),z(z_),
ni(x.size()),
nj(ni ? x[0].size() : 0),
nk(nj ? x[0].size() : 0),
bar( outer_type(ni,middle_type(nj,inner_type(nk))))
{
}
};
成员在构造函数主体执行之前被初始化,这就是我使用成员初始化列表的原因。而且我更改了成员的顺序,因为成员是按照它们在 class 定义中出现的顺序进行初始化的。访问 x[0]
让我有点紧张,所以我试图确保空向量不会造成破坏。
这行得通并且做你想做的(我希望),但是向量中填充了传递给它们的构造函数的临时对象的副本,这不是很有效。作为替代方案,您可以按照
最后一点,如果你真的想要 std::vector<std::vector<std::vector<float>>>
,请重新考虑一下。如果您需要所有“行”具有相同数量的“列”,那么嵌套向量会让您为不使用的东西付费。此外,std::vector
最吸引人的特性是它的内存局部性。但是,std::vector<std::vector<float>>
中的 float
存储在内存的碎片区域中(因为元素没有直接存储在向量中)。
具有适当索引转换的平面 std::vector<float>
通常是更好的选择。
float& access_element(size_t i, size_t j, size_t k) {
return bar[ i *offset_i + j*offset_j + k];
}
您可以使用 resize()
和几个 for 循环来设置 bar
。它不是最漂亮的解决方案,但它应该具有相当不错的性能,因为不会创建临时对象并且没有不必要的分配。看起来像
bar.resize(ni);
for(auto& twodee : bar)
{
twodee.resize(nj);
for(auto& onedee : twodee)
onedee.resize(nk);
}
现在 bar
具有相同的大小并且用零填充。