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

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 倍。这是假设您要创建零向量的可变副本。