嵌套 for_each 循环导致向量大小意外增加
Nested for_each loops causing unexpected increase in size of a vector
我有以下代码用于将二维双精度数组转换为一维向量。使用 std::vector 分配数组,并使用嵌套的 for_each 循环将二维数组的内容传输到一维数组。
#include <iostream>
#include <algorithm>
#include <vector>
#include <stdexcept>
#define UNUSED(expr) (void)(expr)
using usll = __uint64_t;
void print1d(std::vector<double> vv);
void matToVect1d(const std::vector<std::vector<double>>& v2d, std::vector<double>& v1d);
void matToVect1dEx(const std::vector<std::vector<double>>& v2d, std::vector<double>& v1d);
int main(int argc, char* argv[])
{
UNUSED(argc);
UNUSED(argv);
std::cout << std::endl;
const usll DIM0 {10};
const usll DIM1 {8};
std::vector<std::vector<double>> data2d(DIM0, std::vector<double>(DIM1));
std::vector<double> data1d(DIM0 * DIM1);
double temp = 0.0;
for (usll i{}; i<DIM0; ++i)
{
for (usll j{}; j<DIM1; ++j)
{
data2d[i][j] = temp++;
}
}
try
{
matToVect1d(data2d, data1d);
std::cout << "2D array data2d as a 1D vector is:" << std::endl;
print1d(data1d);
std::cout << std::endl;
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
std::cout << "Press enter to continue";
std::cin.get();
return 0;
}
void print1d(std::vector<double> vv)
{
for (size_t i{}; i<vv.size(); ++i)
{
std::cout << vv[i] << " ";
if ((i+1)%10 == 0)
{
std::cout << std::endl;
}
}
std::cout << std::endl;
}
void matToVect1d(const std::vector<std::vector<double>>& v2d, std::vector<double>& v1d)
{
if (v1d.size() != v2d.size()*v2d[0].size())
{
throw std::runtime_error("An exception was caught. The sizes of the input arrays must match.");
}
for_each(v2d.cbegin(), v2d.cend(), [&v1d](const std::vector<double> vec)
{
for_each(vec.cbegin(), vec.cend(), [&v1d](const double& dValue)
{
v1d.emplace_back(dValue);
});
});
}
void matToVect1dEx(const std::vector<std::vector<double>>& v2d, std::vector<double>& v1d)
{
usll index{};
if (v1d.size() != v2d.size()*v2d[0].size())
{
throw std::runtime_error("An exception was caught. The sizes of the input arrays must match.");
}
for (usll i=0; i<v2d.size(); ++i)
{
for (usll j=0; j<v2d[0].size(); ++j)
{
index = j + i*v2d[0].size();
v1d[index] = v2d[i][j];
}
}
}
每次我运行代码,输出是:
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
这是原始一维数组的两倍。什么?零是从哪里来的?是什么导致向量大小从 80 增加到 160?相反,当我将 for_each 循环更改为常规 for 循环时,我得到了正确的输出:
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
我怀疑异常是由于使用了 for_each 算法,然而 Meyer (2018) 在他的书中 Effective C++ Digital Collection: 140 Ways to Improve Your Programming says "the algorithm call is preferable." He says, and I quote: “从效率的角度来看,算法可以通过三种方式击败显式循环,两种主要方式,一种次要方式。次要方式涉及消除
冗余计算。
在我的实际用例中,方法 matToVect1d()
被调用了几次 1000
并且每个数组的元素总数为 240 x 200
。
我的最后一个问题是使用for_each算法实现循环是否有意义?答案将不胜感激。
std::vector<double> data1d(DIM0 * DIM1);
<- 这行代码没有 "reserve"。它用 DIM0 * DIM1
默认初始化双精度值填充向量。
这是您正在使用的构造函数。
vector( size_type count, const T& value, const Allocator& alloc = Allocator());
检查此以获取更多参考:
https://en.cppreference.com/w/cpp/container/vector/vector
改成这样:
std::vector<double> data1d();
data1d.reserve(DIM0 * DIM1);
是因为线
std::vector<double> data1d(DIM0 * DIM1);
其中 data1d
创建一个 向量 double
s 并用 0.0
s in DIM0
x 初始化它DIM0
大小。
因此,稍后在 std::for_each
的情况下,当您 std::vector::emplace_back
时,您将在其后插入元素。因此,您会看到 DIM0
x DIM0
0
s,然后是您插入的元素。
您需要 std::vector::reserve
来实现所需的行为
std::vector<double> data1d;
data1d.reserve(DIM0 * DIM1); // for unwated reallocations
I suspect the anomaly is due to the use of the for_each algorithm[...]
否,原因(即错误)如前所述
My final question is whether it makes sense to implement the loop
using the std::for_each
algorithm?
std::for_each
方法没有任何问题,除了您在第一个 lambdas 参数列表中复制 std::vector<double>
并且(可能)不太可读。
std::for_each(v2d.cbegin(), v2d.cend(), [&v1d](std::vector<double> const& vec)
// ^^^^^^ --> prefer const-ref
{
for_each(vec.cbegin(), vec.cend(), [&v1d](const double dValue)
{
v1d.emplace_back(dValue);
});
});
比下面显示的 range - for-loop
方法
std::vector<double> data1d;
data1d.reserve(DIM0 * DIM1); // for unwated reallocations
// ... later in the function
for (const std::vector<double>& vector : v2d)
for (const double element : vector)
v1d.emplace_back(element);
我有以下代码用于将二维双精度数组转换为一维向量。使用 std::vector 分配数组,并使用嵌套的 for_each 循环将二维数组的内容传输到一维数组。
#include <iostream>
#include <algorithm>
#include <vector>
#include <stdexcept>
#define UNUSED(expr) (void)(expr)
using usll = __uint64_t;
void print1d(std::vector<double> vv);
void matToVect1d(const std::vector<std::vector<double>>& v2d, std::vector<double>& v1d);
void matToVect1dEx(const std::vector<std::vector<double>>& v2d, std::vector<double>& v1d);
int main(int argc, char* argv[])
{
UNUSED(argc);
UNUSED(argv);
std::cout << std::endl;
const usll DIM0 {10};
const usll DIM1 {8};
std::vector<std::vector<double>> data2d(DIM0, std::vector<double>(DIM1));
std::vector<double> data1d(DIM0 * DIM1);
double temp = 0.0;
for (usll i{}; i<DIM0; ++i)
{
for (usll j{}; j<DIM1; ++j)
{
data2d[i][j] = temp++;
}
}
try
{
matToVect1d(data2d, data1d);
std::cout << "2D array data2d as a 1D vector is:" << std::endl;
print1d(data1d);
std::cout << std::endl;
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
}
std::cout << "Press enter to continue";
std::cin.get();
return 0;
}
void print1d(std::vector<double> vv)
{
for (size_t i{}; i<vv.size(); ++i)
{
std::cout << vv[i] << " ";
if ((i+1)%10 == 0)
{
std::cout << std::endl;
}
}
std::cout << std::endl;
}
void matToVect1d(const std::vector<std::vector<double>>& v2d, std::vector<double>& v1d)
{
if (v1d.size() != v2d.size()*v2d[0].size())
{
throw std::runtime_error("An exception was caught. The sizes of the input arrays must match.");
}
for_each(v2d.cbegin(), v2d.cend(), [&v1d](const std::vector<double> vec)
{
for_each(vec.cbegin(), vec.cend(), [&v1d](const double& dValue)
{
v1d.emplace_back(dValue);
});
});
}
void matToVect1dEx(const std::vector<std::vector<double>>& v2d, std::vector<double>& v1d)
{
usll index{};
if (v1d.size() != v2d.size()*v2d[0].size())
{
throw std::runtime_error("An exception was caught. The sizes of the input arrays must match.");
}
for (usll i=0; i<v2d.size(); ++i)
{
for (usll j=0; j<v2d[0].size(); ++j)
{
index = j + i*v2d[0].size();
v1d[index] = v2d[i][j];
}
}
}
每次我运行代码,输出是:
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
这是原始一维数组的两倍。什么?零是从哪里来的?是什么导致向量大小从 80 增加到 160?相反,当我将 for_each 循环更改为常规 for 循环时,我得到了正确的输出:
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
我怀疑异常是由于使用了 for_each 算法,然而 Meyer (2018) 在他的书中 Effective C++ Digital Collection: 140 Ways to Improve Your Programming says "the algorithm call is preferable." He says, and I quote: “从效率的角度来看,算法可以通过三种方式击败显式循环,两种主要方式,一种次要方式。次要方式涉及消除 冗余计算。
在我的实际用例中,方法 matToVect1d()
被调用了几次 1000
并且每个数组的元素总数为 240 x 200
。
我的最后一个问题是使用for_each算法实现循环是否有意义?答案将不胜感激。
std::vector<double> data1d(DIM0 * DIM1);
<- 这行代码没有 "reserve"。它用 DIM0 * DIM1
默认初始化双精度值填充向量。
这是您正在使用的构造函数。
vector( size_type count, const T& value, const Allocator& alloc = Allocator());
检查此以获取更多参考: https://en.cppreference.com/w/cpp/container/vector/vector
改成这样:
std::vector<double> data1d();
data1d.reserve(DIM0 * DIM1);
是因为线
std::vector<double> data1d(DIM0 * DIM1);
其中 data1d
创建一个 向量 double
s 并用 0.0
s in DIM0
x 初始化它DIM0
大小。
因此,稍后在 std::for_each
的情况下,当您 std::vector::emplace_back
时,您将在其后插入元素。因此,您会看到 DIM0
x DIM0
0
s,然后是您插入的元素。
您需要 std::vector::reserve
来实现所需的行为
std::vector<double> data1d;
data1d.reserve(DIM0 * DIM1); // for unwated reallocations
I suspect the anomaly is due to the use of the for_each algorithm[...]
否,原因(即错误)如前所述
My final question is whether it makes sense to implement the loop using the
std::for_each
algorithm?
std::for_each
方法没有任何问题,除了您在第一个 lambdas 参数列表中复制 std::vector<double>
并且(可能)不太可读。
std::for_each(v2d.cbegin(), v2d.cend(), [&v1d](std::vector<double> const& vec)
// ^^^^^^ --> prefer const-ref
{
for_each(vec.cbegin(), vec.cend(), [&v1d](const double dValue)
{
v1d.emplace_back(dValue);
});
});
比下面显示的 range - for-loop
方法
std::vector<double> data1d;
data1d.reserve(DIM0 * DIM1); // for unwated reallocations
// ... later in the function
for (const std::vector<double>& vector : v2d)
for (const double element : vector)
v1d.emplace_back(element);