每次选择参数时调用一次的静态变量和函数

Static variables and functions that are called once for each choice of arguments

本文关键字:一次 静态 函数 变量 参数 选择 调用      更新时间:2023-10-16

这是一个简单的c++问题。

问题描述:我有一个函数,它接受一个整数作为输入,然后返回一个长度为0的向量作为输入。假设我用相同的参数多次调用该函数。我要避免的是每次调用函数都会产生一个0向量。我希望这只发生在第一次调用给定输入的函数时。

如何处理:这让我想起了静态变量。我想过创建一个静态向量来保存每种大小的所需零向量,但不知道如何实现这一点。作为一个例子,我想要的东西"看起来"像[[0],[0,0],…]。

如果有不同的方法来解决这样的问题,请随时分享!此外,我的例子与向量是有点专业化,但答复是更通用的(涉及依赖于参数的静态变量)将非常感谢。

一边问:进一步概括一下,是否有可能定义一个函数,对于每个选择的参数只调用一次 ?

可以有一个大小和向量的映射,每个大小对应一个向量:

#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;
}

如果我正确理解了你的意图,我认为你不会得到你所期望的好处。

我编写了一个快速基准测试来比较重复创建零向量的性能。第一个基准测试使用标准向量构造函数。第二个函数只在第一次创建vector对象,并将其存储在map对象中:

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倍。这是假设您想要创建一个包含0的向量的可变副本。

如果每个向量需要是一个单独的实例,那么你必须为每个实例都有一个构造。因为您必须构造每个实例,所以您可以创建一个简单的make_int_vector函数,如:

std::vector<int> make_int_vector(std::size_t size, int fill = 0) 
{ 
    return std::vector(size, fill); 
}

返回的向量要么被移动,要么被省略

您要求的是缓存。困难的部分是条目应该在缓存中存在多长时间。您当前的需求似乎是一个永久缓存,这意味着每个条目将永远存在。对于这样一个简单的用例,使用静态映射就足够了:

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];
}

上面返回的是一个值,需要复制。如果你想避免复制,只需返回一个引用,但是,如果你改变了其中一个vector,下一次调用将返回修改后的值。

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];
}