C++:从vector<vector<T>>获取T**
Posted
技术标签:
【中文标题】C++:从vector<vector<T>>获取T**【英文标题】:C++: Getting T** from vector<vector<T>> 【发布时间】:2017-10-24 01:15:04 【问题描述】:我正在与需要float**
类型的二维数组的 C 库交互,其大小在运行时确定。我想使用诸如 std::vector 之类的 STL 容器来管理此内存,但 vector<vector<float>>::data()
提供 vector<float>*
,而不是 float**
。我能做什么?
【问题讨论】:
分配您自己的float**
或vector<float*>
并用指向内部向量data()
的指针填充它。您不能免费获得float**
- 它只是不存在于您选择的数据结构中。
请问为什么我的问题被否决了?我非常努力地简洁地提出这个问题,并在发布之前进行了广泛的搜索。我怎么能做得更好?公认的答案很有趣且有见地。不明白为什么这篇文章不受欢迎......
【参考方案1】:
您可以创建一个新的 vector,其中包含指向由您的 vector of vectors 的内部 vector 管理的所有内部数组的指针:
void old_c_function(float** floats, std::size_t X, std::size_t Y)
for(auto x = 0U; x < X; ++x)
for(auto y = 0U; y < Y; ++y)
std::cout << "[" << x << ", " << y << "] = " << floats[x][y] << '\n';
int main()
std::vector<std::vector<float>> v =
1.2, 3.4, 5.6,
7.8, 9.0, 1.2,
;
// create a new vector to hold the pointers to the arrays
// managed by the internal vectors
std::vector<float*> v_ptrs;
v_ptrs.reserve(v.size());
// add the addresses of all the arrays to the new vector
std::for_each(std::begin(v), std::end(v),
[&v_ptrs](auto& v) v_ptrs.push_back(v.data()); );
// call your legacy function using your pointer vector
old_c_function(v_ptrs.data(), v.size(), v.front().size());
输出:
[0, 0] = 1.2
[0, 1] = 3.4
[0, 2] = 5.6
[1, 0] = 7.8
[1, 1] = 9
[1, 2] = 1.2
注意:
显然,如果您更改向量,则需要重建指针向量,因为地址可能会发生变化。
您可以通过一些包装函数即时重建它,如下所示:
void new_wrapper_function(std::vector<std::vector<float>>& v)
// create a new vector to hold the pointers to the arrays
// managed by the internal vectors
std::vector<float*> v_ptrs;
v_ptrs.reserve(v.size());
// add the addresses of all the arrays to the new vector
std::for_each(std::begin(v), std::end(v)
[&v_ptrs](auto& v) v_ptrs.push_back(v.data()); );
// call your legacy function using your pointer vector
old_c_function(v_ptrs.data(), v.size(), v.front().size());
或者(我最喜欢的)构建一个包装器 class
来封装两个向量,并在主向量在其一个维度上增加容量时更新指针向量。
【讨论】:
... 然后您希望 C 函数只是有一个草率的声明,实际上将其参数视为float* const*
。
@aschepler C 函数可以毫无问题地更新数组,指针指向原始数组中的实际数据。
std::copy
到 std::back_inserter(v)
怎么样?
@aschepler 因为我没有复制float
值,所以我正在获取每个内部数组的第一个元素的地址。
哦,呵呵。 std::vector<float>
不会很好地初始化 float*
。没有。【参考方案2】:
我会说使用
typedef std::pair<int, int> shape;
std::pair<float **, shape> obj;
或
std::tuple<float **, int, int> obj;
随你喜欢。
【讨论】:
【参考方案3】:我能做什么?
a) 使用一维向量
typedef std::vector<float> FloatVec_t
b) 要访问一维向量,您可以从二维坐标计算一维索引,这是一个可以优化掉的简单函数。
// size_t maxCol; is runtime size info
size_t indx1D(size_t r, size_t c)
return static_cast<size_t>((r*maxCol) + c);
c) 创建/使用 getElement(x,y) 进行二维访问:
FloatVec_t fltVec1D;
// 2d access
float* getElement(size_t r, size_t c) return (fltVec [indx1D (r,c)]);
d) 在一维向量之上创建 arr。请参阅下面的工作代码。
环境:
Ubuntu 15.10; g++ 版本 5.2.1 20151028;旧版戴尔速龙
代码/MCVE:
#include "../../bag/src/dtb_chrono.hh"
#include <iostream>
#include <iomanip>
#include <vector>
#include <cassert>
typedef std::vector<float> FloatVec_t;
class T537_t
private:
FloatVec_t fltVec1D;
size_t maxCol;
size_t maxRow;
public:
T537_t () = default;
~T537_t() = default;
int exec(size_t a_MaxCol,
size_t a_MaxRow)
maxCol = a_MaxCol;
maxRow = a_MaxRow;
size_t N = maxCol * maxRow;
std::cout << "\n sizeof(float): " << sizeof(float) << std::endl;
std::cout << "\n Col x Row: " << maxCol << " x " << maxRow
<< " = " << N
<< "\n\n reserved " << N << " elements in 1D vec" << std::endl;
fltVec1D.reserve(N);
std::cout << "\n initialize 1D vec with values computed from row and col" << std::flush;
for (uint r=1; r<=maxRow; ++r)
for (uint c=1; c<=maxCol; ++c)
fltVec1D.push_back (100.1F * static_cast<float> (((r-1)*maxCol) + c));
std::cout << "\n\n report fltVec1D addrs: " << std::flush;
for (uint r=0; r<maxRow; ++r)
std::cout << "\n fltVec1D[" << std::setw(2) << r << "] " << std::flush;
for (uint c=0; c<maxCol; ++c)
std::cout << " " << std::setw(8)
<< &fltVec1D[indx1D(r,c)] << std::flush;
std::cout << std::flush;
std::cout << "\n\n report fltVec1D data: " << std::flush;
for (uint r=0; r<maxRow; ++r)
std::cout << "\n fltVec1D[" << std::setw(2) << r << "] " << std::flush;
for (uint c=0; c<maxCol; ++c)
std::cout << " " << std::setw(8) << std::setprecision(5)
<< fltVec1D[indx1D(r,c)] << std::flush;
std::cout << std::flush;
// overlay arr on top of fltVec1D data
float** arr = new float* [maxRow]; // arr contains rows
for (size_t r=0; r < maxRow; ++r)
arr[r] = getElement(r,0); // rows already exist
// and start at col 0,
std::cout << "\n\n report arr data: " << std::flush;
for (size_t r=0; r<maxRow; ++r)
std::cout << "\n arr[" << std::setw(2) << r << "] " << std::flush;
for (size_t c=0; c<maxCol; ++c)
std::cout << " " << std::setw(8) << std::setprecision(5)
<< arr[r][c] << std::flush;
std::cout << std::flush;
std::cout << "\n\n\n report address diffs: &arr[r][c] - getElement(r,c) : \n" << std::flush;
for (uint r=0; r<maxRow; ++r)
std::cout << "\n row" << std::setw(2) << r << " " << std::flush;
for (uint c=0; c<maxCol; ++c)
float* addr1 = & arr[r][c];
float* addr2 = getElement(r,c);
std::cout << " " << std::setw(8) << (addr1 - addr2) << std::flush;
std::cout << std::flush;
delete[] arr; // delete of float** arr = new float* [maxCol];
return 0;
private: // methods
size_t indx1D(size_t r, size_t c)
assert(r<maxRow);
assert(c<maxCol);
return static_cast<size_t>((r*maxCol) + c);
float* getElement(size_t r, size_t c) return (& fltVec1D [indx1D(r,c) ] );
; // class T537_t
int main(int argc, char* argv[])
if(argc > 1)
std::cout << "\nargc: " << argc << std::endl;
for (int i = 0; i < argc; i += 1) std::cout << argv[i] << " ";
std::cout << std::endl;
if(3 != argc)
std::cerr << "\n 2 Required parameters: maxCol maxRow " << std::endl;
return (0);
setlocale(LC_ALL, "");
std::ios::sync_with_stdio(false);
int retVal = -1;
T537_t t537;
Time_t start_us = HRClk_t::now();
retVal = t537.exec(static_cast<size_t>(std::atoi(argv[1])), // col - i.e. 5
static_cast<size_t>(std::atoi(argv[2]))); // row - i.e. 20
auto duration_us = std::chrono::duration_cast<US_t>(HRClk_t::now() - start_us);
std::cout << "\n\n t537.exec() duration " << duration_us.count() << " us" << std::endl;
return(retVal);
命令行参数的输出示例 3 5
sizeof(float): 4
Col x Row: 3 x 5 = 15
reserved 15 elements in 1D vec
initialize 1D vec with values computed from row and col
report fltVec1D addrs:
fltVec1D[ 0] 0x179dc50 0x179dc54 0x179dc58
fltVec1D[ 1] 0x179dc5c 0x179dc60 0x179dc64
fltVec1D[ 2] 0x179dc68 0x179dc6c 0x179dc70
fltVec1D[ 3] 0x179dc74 0x179dc78 0x179dc7c
fltVec1D[ 4] 0x179dc80 0x179dc84 0x179dc88
report fltVec1D data:
fltVec1D[ 0] 100.1 200.2 300.3
fltVec1D[ 1] 400.4 500.5 600.6
fltVec1D[ 2] 700.7 800.8 900.9
fltVec1D[ 3] 1001 1101.1 1201.2
fltVec1D[ 4] 1301.3 1401.4 1501.5
report arr data:
arr[ 0] 100.1 200.2 300.3
arr[ 1] 400.4 500.5 600.6
arr[ 2] 700.7 800.8 900.9
arr[ 3] 1001 1101.1 1201.2
arr[ 4] 1301.3 1401.4 1501.5
report address diffs: &arr[r][c] - getElement(r,c) :
row 0 0 0 0
row 1 0 0 0
row 2 0 0 0
row 3 0 0 0
row 4 0 0 0
总结:
本单元测试代码演示:
a) 构建并初始化一维 std::vector。
b) 使用内置数组构造和 new 创建“float** arr”。
c) 快速 for 循环使用 getElement(r,0) 加载每个行指针。
d) 单元测试显示来自 1d vec (fltVec1D) 和 arr 的相同信息(地址和数据)
e) 测试通过比较地址来结束,这表明这两个名称提供了对相同地址和相同数据的访问。
“arr”适用于交付给遗留功能(未测试)。
【讨论】:
这如何帮助将某些内容传递给需要float**
的现有函数?
通常当函数文档声称 float** p
表示一个 mxn 二维数组时,这意味着元素是 p[i][j]
其中 i<m && j<n
,而不是 *p[i*n+j]
。 (是的,所以这里不涉及数组数组。不过。)
@aschepler - 感谢您的问题和评论.. 我决定提供一些代码,并且不得不寻找它,然后修改它。以上是关于C++:从vector<vector<T>>获取T**的主要内容,如果未能解决你的问题,请参考以下文章
从 Swift 调用 C++ - std::vector<T> 的等价物
C++ - 迭代从 find_if 返回的 std::vector<>