避免手动创建 lambda 来包装对 new[]: 的调用,以用作 std::generate 中的生成器函数
Avoid manual creation of lambda to wrap the call to new[]: to be used as a generator function in std::generate
精简版
目前,我为new []
手动创建了一个lambda函数,如下:
[](){ return new double[3]; }
此 lambda 稍后在对 std::generate
的调用中用作生成器函数:
std::generate(vec.begin(), vec.end(), [](){ return new double[3]; });
我可以避免创建这个 lambda 并使用一些更标准的 functionality/syntax sugar/alternatives 吗? C++17 是首选;但是,如果 C++20(或某些提案)提供更好的东西,我也很感兴趣。
长版本提供了一些背景知识,以及针对类似情况的现有解决方案,当 for_each
用于释放内存时。
带背景的长版
需要
- 创建
std::vector
存储 double*
指针,指向固定大小的一维数组。
- 将此结构传递给将用数据填充它的库函数。
- 使用填充的数据。
- 清除分配的内存。
条件
- 由于 (2),我无法控制库函数的参数类型;因此,无论其他容器如何更适合,我都只能使用
std::vector<double*>
。
- 想要干净、简约和高效的代码
- 特别是,我从简单的普通
for
循环开始,然后决定使用 STL <algorithm>
。
初始代码
#include <vector>
int main()
{
// (1)
size_t numElems = 10;
std::vector<double*> vec(numElems);
for (size_t i=0; i<numElems; i++)
{
vec[i] = new double[3];
}
// (2)-(3) SOME ACTIVITY with vec
// (4)
for (size_t i=0; i<numElems; i++)
{
delete [] vec[i];
}
}
其中,为简单起见,我将 numElems
硬编码在向量 vec
中,并将 double*
数组的大小硬编码为 3
。 (2)-(3) 中传递给外部函数和 activity 被跳过。此代码有效。
新代码
我尝试了以下方法:
#include <vector>
#include <algorithm>
#include <memory>
int main()
{
// (1)
size_t numElems = 10;
std::vector<double*> vec(numElems);
std::generate(vec.begin(), vec.end(), [](){ return new double[3]; });
// (2)-(3) SOME ACTIVITY with vec
// (4)
std::for_each(vec.begin(), vec.end(), std::default_delete<double[]>());
}
这也很好用。
问题
修改后的版本,通过std::default_delete<>
applied via std::for_each
删除,方便提供语言关键字delete []
的“函数表示”(有点草率)
是否有类似的方式“表示”new []
?或者我是否坚持手动创建 lambda 以用作 std::generate
的生成器函数参数?
以下:
#include <type_traits>
#include <vector>
#include <algorithm>
#include <memory>
template<typename T>
struct default_new {
typename std::decay<T>::type operator() (){ return new T; }
};
int main() {
size_t numElems = 10;
std::vector<double*> vec(numElems);
std::generate(vec.begin(), vec.end(), default_new<double[3]>());
// (2)-(3) SOME ACTIVITY with vec
// (4)
std::for_each(vec.begin(), vec.end(), std::default_delete<double[]>());
}
有效。不知道标准库有没有提供,我相信没有。
单个堆分配在内存开销中花费了几个指针值每个元素。因此,如果您正在处理一个巨大的指针向量,它可能会节省内存以进行一次分配,并将一个向量作为视图:
struct vector3 {
vector3(size_t numElements)
// use new[] over std::make_unique to avoid value initialization,
// since it's assumed the library function will initialize the data
: storage(new std::array<double, 3>[numElements]) {
view.reserve(numElements);
std::transform(
storage.get(),
storage.get() + numElements,
std::back_inserter(view),
[](auto& a) { return a.data(); }); // no good substitute for lambda here
}
std::unique_ptr<std::array<double, 3>[]> storage;
std::vector<double*> view;
};
用法:
vector3 myVector(10);
library_function(myVector.view);
演示:https://godbolt.org/z/6x4PEs
编辑:移至 class 以根据 Swift - Friday Pie 的建议保证生命周期。
精简版
目前,我为new []
手动创建了一个lambda函数,如下:
[](){ return new double[3]; }
此 lambda 稍后在对 std::generate
的调用中用作生成器函数:
std::generate(vec.begin(), vec.end(), [](){ return new double[3]; });
我可以避免创建这个 lambda 并使用一些更标准的 functionality/syntax sugar/alternatives 吗? C++17 是首选;但是,如果 C++20(或某些提案)提供更好的东西,我也很感兴趣。
长版本提供了一些背景知识,以及针对类似情况的现有解决方案,当 for_each
用于释放内存时。
带背景的长版
需要
- 创建
std::vector
存储double*
指针,指向固定大小的一维数组。 - 将此结构传递给将用数据填充它的库函数。
- 使用填充的数据。
- 清除分配的内存。
条件
- 由于 (2),我无法控制库函数的参数类型;因此,无论其他容器如何更适合,我都只能使用
std::vector<double*>
。 - 想要干净、简约和高效的代码
- 特别是,我从简单的普通
for
循环开始,然后决定使用 STL<algorithm>
。
初始代码
#include <vector>
int main()
{
// (1)
size_t numElems = 10;
std::vector<double*> vec(numElems);
for (size_t i=0; i<numElems; i++)
{
vec[i] = new double[3];
}
// (2)-(3) SOME ACTIVITY with vec
// (4)
for (size_t i=0; i<numElems; i++)
{
delete [] vec[i];
}
}
其中,为简单起见,我将 numElems
硬编码在向量 vec
中,并将 double*
数组的大小硬编码为 3
。 (2)-(3) 中传递给外部函数和 activity 被跳过。此代码有效。
新代码
我尝试了以下方法:
#include <vector>
#include <algorithm>
#include <memory>
int main()
{
// (1)
size_t numElems = 10;
std::vector<double*> vec(numElems);
std::generate(vec.begin(), vec.end(), [](){ return new double[3]; });
// (2)-(3) SOME ACTIVITY with vec
// (4)
std::for_each(vec.begin(), vec.end(), std::default_delete<double[]>());
}
这也很好用。
问题
修改后的版本,通过std::default_delete<>
applied via std::for_each
删除,方便提供语言关键字delete []
的“函数表示”(有点草率)
是否有类似的方式“表示”new []
?或者我是否坚持手动创建 lambda 以用作 std::generate
的生成器函数参数?
以下:
#include <type_traits>
#include <vector>
#include <algorithm>
#include <memory>
template<typename T>
struct default_new {
typename std::decay<T>::type operator() (){ return new T; }
};
int main() {
size_t numElems = 10;
std::vector<double*> vec(numElems);
std::generate(vec.begin(), vec.end(), default_new<double[3]>());
// (2)-(3) SOME ACTIVITY with vec
// (4)
std::for_each(vec.begin(), vec.end(), std::default_delete<double[]>());
}
有效。不知道标准库有没有提供,我相信没有。
单个堆分配在内存开销中花费了几个指针值每个元素。因此,如果您正在处理一个巨大的指针向量,它可能会节省内存以进行一次分配,并将一个向量作为视图:
struct vector3 {
vector3(size_t numElements)
// use new[] over std::make_unique to avoid value initialization,
// since it's assumed the library function will initialize the data
: storage(new std::array<double, 3>[numElements]) {
view.reserve(numElements);
std::transform(
storage.get(),
storage.get() + numElements,
std::back_inserter(view),
[](auto& a) { return a.data(); }); // no good substitute for lambda here
}
std::unique_ptr<std::array<double, 3>[]> storage;
std::vector<double*> view;
};
用法:
vector3 myVector(10);
library_function(myVector.view);
演示:https://godbolt.org/z/6x4PEs
编辑:移至 class 以根据 Swift - Friday Pie 的建议保证生命周期。