为每个参数选择调用一次的静态变量和函数
Static variables and functions that are called once for each choice of arguments
这是一个简单的 C++ 问题。
问题描述:
我有一个函数,它将一个整数和 returns 一个长度为输入的零向量作为输入。假设我使用相同的参数多次调用该函数。我想避免的是我的函数每次调用时都会创建零向量。我希望这仅在第一次使用给定输入调用函数时发生。
我是如何处理它的: 这让我想起了静态变量。我想创建一个静态向量来保存每个大小所需的零向量,但无法弄清楚如何实现它。例如,我想要 "looks" 之类的东西 [ [0], [0,0], ...].
如果有解决此类问题的不同方法,请随时分享!此外,我的矢量示例有点专业化,但更通用的回复(关于依赖于参数的静态变量)将不胜感激。
附带问题:
为了进一步概括,是否可以定义一个函数,该函数只为每个参数选择调用 一次?
非常感谢。
如果每个向量都需要是一个单独的实例,那么您必须为每个实例创建一个结构。由于您必须构建每个实例,因此您可以创建一个简单的 make_int_vector
函数,例如:
std::vector<int> make_int_vector(std::size_t size, int fill = 0)
{
return std::vector(size, fill);
}
返回的矢量将被移动或用 copy elision
省略
你可以有一张尺寸和矢量的地图,每个尺寸一个矢量:
#include <vector>
#include <map>
#include <cstddef>
std::vector<int>& get_vector(std::size_t size)
{
static std::map<size_t, std::vector<int> > vectors;
std::map<size_t, std::vector<int> >::iterator iter = vectors.find(size);
if (iter == vectors.end())
{
iter = vectors.insert(std::make_pair(size, std::vector<int>(size, 0))).first;
}
return iter->second;
}
您要的是缓存。困难的部分是一个条目应该在缓存中存在多长时间。您当前的要求似乎是一个永恒的缓存,这意味着每个条目都将永远存在。对于这样一个简单的用例,静态地图就足够了:
template<typename T, typename U>
T cached(T (*funct)(U arg)) {
static unordered_map<U, T> c;
if (c.count(arg) == 0) {
c[arg] = funct(arg);
}
return c[arg];
}
以上是return取值,需要复制。如果你想避免复制,只需 return 一个引用,但是,如果你更改其中一个向量,下一次调用将 return 修改后的值。
template<typename T, typename U>
&T cached(T (*funct)(U arg)) {
static unordered_map<U, T> c;
if (c.count(arg) == 0) {
c[arg] = funct(arg);
}
return c[arg];
}
如果我正确理解了您正在尝试做的事情,我认为您不会得到您期望的收益。
我写了一个快速基准来比较重复创建零向量的性能。第一个基准测试使用标准向量构造函数。第二种使用的函数只在第一次创建向量并将其存储在映射中:
const std::vector<int>& zeros(std::size_t size) {
static std::unordered_map<size_t, std::vector<int>> vectors;
auto find = vectors.find(size);
if (find != vectors.end())
return find->second;
auto insert = vectors.emplace(size, std::vector<int>(size));
return insert.first->second;
}
std::chrono::duration<float> benchmarkUsingMap() {
int sum = 0;
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i != 10'000; ++i) {
auto zeros10k = zeros(10'000);
zeros10k[5342] = 1;
sum += zeros10k[5342];
}
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Sum: " << sum << "\n";
return end - start;
}
std::chrono::duration<float> benchmarkWithoutUsingMap() {
int sum = 0;
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i != 10'000; ++i) {
auto zeros10k = std::vector<int>(10'000);
zeros10k[5342] = 1;
sum += zeros10k[5342];
}
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Sum: " << sum << "\n";
return end - start;
}
int main() {
std::cout << "Benchmark without map: " << benchmarkWithoutUsingMap().count() << '\n';
std::cout << "Benchmark using map: " << benchmarkUsingMap().count() << '\n';
}
输出:
Benchmark without map: 0.0188374
Benchmark using map: 0.134966
因此,在这种情况下,每次创建向量的速度几乎快了 10 倍。这是假设您要创建零向量的可变副本。
这是一个简单的 C++ 问题。
问题描述: 我有一个函数,它将一个整数和 returns 一个长度为输入的零向量作为输入。假设我使用相同的参数多次调用该函数。我想避免的是我的函数每次调用时都会创建零向量。我希望这仅在第一次使用给定输入调用函数时发生。
我是如何处理它的: 这让我想起了静态变量。我想创建一个静态向量来保存每个大小所需的零向量,但无法弄清楚如何实现它。例如,我想要 "looks" 之类的东西 [ [0], [0,0], ...].
如果有解决此类问题的不同方法,请随时分享!此外,我的矢量示例有点专业化,但更通用的回复(关于依赖于参数的静态变量)将不胜感激。
附带问题: 为了进一步概括,是否可以定义一个函数,该函数只为每个参数选择调用 一次?
非常感谢。
如果每个向量都需要是一个单独的实例,那么您必须为每个实例创建一个结构。由于您必须构建每个实例,因此您可以创建一个简单的 make_int_vector
函数,例如:
std::vector<int> make_int_vector(std::size_t size, int fill = 0)
{
return std::vector(size, fill);
}
返回的矢量将被移动或用 copy elision
省略你可以有一张尺寸和矢量的地图,每个尺寸一个矢量:
#include <vector>
#include <map>
#include <cstddef>
std::vector<int>& get_vector(std::size_t size)
{
static std::map<size_t, std::vector<int> > vectors;
std::map<size_t, std::vector<int> >::iterator iter = vectors.find(size);
if (iter == vectors.end())
{
iter = vectors.insert(std::make_pair(size, std::vector<int>(size, 0))).first;
}
return iter->second;
}
您要的是缓存。困难的部分是一个条目应该在缓存中存在多长时间。您当前的要求似乎是一个永恒的缓存,这意味着每个条目都将永远存在。对于这样一个简单的用例,静态地图就足够了:
template<typename T, typename U>
T cached(T (*funct)(U arg)) {
static unordered_map<U, T> c;
if (c.count(arg) == 0) {
c[arg] = funct(arg);
}
return c[arg];
}
以上是return取值,需要复制。如果你想避免复制,只需 return 一个引用,但是,如果你更改其中一个向量,下一次调用将 return 修改后的值。
template<typename T, typename U>
&T cached(T (*funct)(U arg)) {
static unordered_map<U, T> c;
if (c.count(arg) == 0) {
c[arg] = funct(arg);
}
return c[arg];
}
如果我正确理解了您正在尝试做的事情,我认为您不会得到您期望的收益。
我写了一个快速基准来比较重复创建零向量的性能。第一个基准测试使用标准向量构造函数。第二种使用的函数只在第一次创建向量并将其存储在映射中:
const std::vector<int>& zeros(std::size_t size) {
static std::unordered_map<size_t, std::vector<int>> vectors;
auto find = vectors.find(size);
if (find != vectors.end())
return find->second;
auto insert = vectors.emplace(size, std::vector<int>(size));
return insert.first->second;
}
std::chrono::duration<float> benchmarkUsingMap() {
int sum = 0;
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i != 10'000; ++i) {
auto zeros10k = zeros(10'000);
zeros10k[5342] = 1;
sum += zeros10k[5342];
}
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Sum: " << sum << "\n";
return end - start;
}
std::chrono::duration<float> benchmarkWithoutUsingMap() {
int sum = 0;
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i != 10'000; ++i) {
auto zeros10k = std::vector<int>(10'000);
zeros10k[5342] = 1;
sum += zeros10k[5342];
}
auto end = std::chrono::high_resolution_clock::now();
std::cout << "Sum: " << sum << "\n";
return end - start;
}
int main() {
std::cout << "Benchmark without map: " << benchmarkWithoutUsingMap().count() << '\n';
std::cout << "Benchmark using map: " << benchmarkUsingMap().count() << '\n';
}
输出:
Benchmark without map: 0.0188374
Benchmark using map: 0.134966
因此,在这种情况下,每次创建向量的速度几乎快了 10 倍。这是假设您要创建零向量的可变副本。