从初始化列表中填充 boost::multi_array 的最佳方法是什么?
What is the best way to populate a boost::multi_array from an initializer list?
我想在某些代码中初始化 boost::multi_array 内联。但我认为 boost::multi_array 不支持从初始化列表中进行初始化。这是我目前所拥有的:
// First create a primitive array, which can be directly initialized
uint8_t field_primitive[4][8] = {
{ 1,1,1,1,1,1,1,1 },
{ 1,2,1,2,1,2,1,2 },
{ 1,1,2,2,2,2,2,2 },
{ 1,2,2,2,2,2,2,2 }
};
// Create the boost::multi_array I actually want to use
boost::multi_array<uint8_t, 2> field(boost::extents[4][8]);
// Compact but yucky approach to copying the primitive array contents into the multi_array.
memcpy(field.data(), field_primitive, field.num_elements() * sizeof(uint8_t));
我喜欢我可以使用花括号初始化器列表紧凑地表达矩阵内容。但我不喜欢 "memcpy",也不喜欢使用一次性原始数组。有没有更好的方法从代码中可读的内联值集填充我的 boost::multi_array?
官方 boost 文档中有关 multi_array 的以下示例也使用了 memcpy
,但与 origin()
结合使用。所以用起来好像没问题:
#include <boost/multi_array.hpp>
#include <algorithm>
#include <iostream>
#include <cstring>
int main()
{
boost::multi_array<char, 2> a{boost::extents[2][6]};
typedef boost::multi_array<char, 2>::array_view<1>::type array_view;
typedef boost::multi_array_types::index_range range;
array_view view = a[boost::indices[0][range{0, 5}]];
std::memcpy(view.origin(), "tsooB", 6);
std::reverse(view.begin(), view.end());
std::cout << view.origin() << '\n';
boost::multi_array<char, 2>::reference subarray = a[1];
std::memcpy(subarray.origin(), "C++", 4);
std::cout << subarray.origin() << '\n';
}
关于origin()
和data()
的区别,multiarray reference manual定义如下:
element* data(); This returns a pointer to the beginning of the
contiguous block that contains the array's data. If all dimensions of
the array are 0-indexed and stored in ascending order, this is
equivalent to origin().
element* origin(); This returns the origin element of the multi_array.
因此,在将 data()
和 origin()
与 memcpy
一起使用时,似乎有两件事需要考虑,前提是数组包含非 0 索引或非升序维度顺序:
首先,origin()
可能没有指向数组使用的连续内存块的开始。因此,将多数组大小的内存复制到此位置可能会超出保留的内存块。
其次,另一方面,将内存块复制到 data()
的地址可能会导致内存布局,其中通过 multiarray 访问的数组索引与复制到的内存块的索引不对应数组的内部数据缓冲区。
所以在我看来,使用 memcpy
来(预)填充多数组应该小心使用,最好使用基于 0 的索引和升序。
我想在某些代码中初始化 boost::multi_array 内联。但我认为 boost::multi_array 不支持从初始化列表中进行初始化。这是我目前所拥有的:
// First create a primitive array, which can be directly initialized
uint8_t field_primitive[4][8] = {
{ 1,1,1,1,1,1,1,1 },
{ 1,2,1,2,1,2,1,2 },
{ 1,1,2,2,2,2,2,2 },
{ 1,2,2,2,2,2,2,2 }
};
// Create the boost::multi_array I actually want to use
boost::multi_array<uint8_t, 2> field(boost::extents[4][8]);
// Compact but yucky approach to copying the primitive array contents into the multi_array.
memcpy(field.data(), field_primitive, field.num_elements() * sizeof(uint8_t));
我喜欢我可以使用花括号初始化器列表紧凑地表达矩阵内容。但我不喜欢 "memcpy",也不喜欢使用一次性原始数组。有没有更好的方法从代码中可读的内联值集填充我的 boost::multi_array?
官方 boost 文档中有关 multi_array 的以下示例也使用了 memcpy
,但与 origin()
结合使用。所以用起来好像没问题:
#include <boost/multi_array.hpp>
#include <algorithm>
#include <iostream>
#include <cstring>
int main()
{
boost::multi_array<char, 2> a{boost::extents[2][6]};
typedef boost::multi_array<char, 2>::array_view<1>::type array_view;
typedef boost::multi_array_types::index_range range;
array_view view = a[boost::indices[0][range{0, 5}]];
std::memcpy(view.origin(), "tsooB", 6);
std::reverse(view.begin(), view.end());
std::cout << view.origin() << '\n';
boost::multi_array<char, 2>::reference subarray = a[1];
std::memcpy(subarray.origin(), "C++", 4);
std::cout << subarray.origin() << '\n';
}
关于origin()
和data()
的区别,multiarray reference manual定义如下:
element* data(); This returns a pointer to the beginning of the contiguous block that contains the array's data. If all dimensions of the array are 0-indexed and stored in ascending order, this is equivalent to origin().
element* origin(); This returns the origin element of the multi_array.
因此,在将 data()
和 origin()
与 memcpy
一起使用时,似乎有两件事需要考虑,前提是数组包含非 0 索引或非升序维度顺序:
首先,origin()
可能没有指向数组使用的连续内存块的开始。因此,将多数组大小的内存复制到此位置可能会超出保留的内存块。
其次,另一方面,将内存块复制到 data()
的地址可能会导致内存布局,其中通过 multiarray 访问的数组索引与复制到的内存块的索引不对应数组的内部数据缓冲区。
所以在我看来,使用 memcpy
来(预)填充多数组应该小心使用,最好使用基于 0 的索引和升序。