一度確保した領域を使い回す

初期化に時間がかかったり、そもそもメモリを確保する時間が問題になる場合、
一度確保したインスタンスは使い回したい。

## 毎回確保する
あるクラス`A`のインスタンスが計算の一時領域として必要だとする。

```cpp
void func(int N){
  A a(N);
  ...
}
```

これだとこの関数が呼ばれるたびに初期化が必要となる。
この関数が何回も呼ばれるとすると、new/deleteのコストが無視できない事もある。
そんな場合にどうするかが今回の主題である。

## 静的に確保する

```cpp
void func(int N){
  static A a(N);
  ...
}
```

これで初期化は最初に呼ばれた時だけになる。
しかし問題が2つある：

- 初期化のための引数が最初の一回しか渡せない
- このような関数が複数あったとき、関数毎に静的変数が生成されメモリを沢山使う

## 関数オブジェクトにする

```cpp
class func{
  A a;
public:
  func(int N): a(N) {}
  void operator(){
    ...
  }
};
```

これも静的に確保してるのと同様である。

## 一度確保したインスタンスを使い回す

以上の不満を解決するには、
一旦確保したインスタンスをその引数と共に覚えておく人がいて、
各関数はその人から一時的に借りてこれたらいい。
という事でこんなクラスを作る：

```cpp:Rotary.hpp
#include <vector>
#include <memory>
#include <boost/any.hpp>

template <class T> class Rotary {
  /** 確保したインスタンスを引数と共に保持する */
  struct Item {
    bool isFree; // 貸し出しているか
    boost::any args; // 引数
    T *ptr; // インスタンスのポインタ
  };
  std::vector<Item> items;

  Rotary() {};
  ~Rotary() {
    for (auto &i : items) {
      delete i.ptr;
    }
  }

  Rotary(const Rotary &) = delete;
  Rotary(Rotary &&) = delete;

private:
  /** 借りたメモリを返却する */
  static void release(T *p) {
    auto &man = getRef();
    for (auto &i : man.items) {
      if (p == i.ptr)
        i.isFree = true;
    }
  }

public:
  /** 自動的に返却される */
  typedef std::unique_ptr<T, decltype(&release)> Pointer;

private:
  /** 貸し出す */
  template <typename... Args> Pointer rent_dyn(Args... args) {
    typedef std::tuple<Args...> Tuple;
    Tuple t = std::make_tuple(args...);
    for (auto &i : items) {
      if (i.isFree && typeid(Tuple) == i.args.type() &&
          t == boost::any_cast<Tuple>(i.args)) {
        i.isFree = false;
        return Pointer(i.ptr, release);
      }
    } // 既に確保したインスタンスの内、貸し出していないのがあればそれを貸す
    /* 無ければ新しく用意する */
    T *mem = new T(args...);
    items.push_back({ false, t, mem });
    return Pointer(mem, release);
  }

  static Rotary<T> &getRef() {
    static Rotary<T> rot; // singleton (スレッドセーフではない)
    return rot;
  }

public:
  template <typename... Args> static Pointer rent(Args... args) {
    return getRef().rent_dyn(args...);
  }
};
```

```cpp
#include "Rotary.hpp"
#include <iostream>

typedef Rotary<std::vector<int> > Rot;

void func1(int N) {
  auto tmp1 = Rot::rent(N);
  std::cout << tmp1->size() << std::endl;
  std::cout << tmp1.get() << std::endl;
}

void func2(int N) {
  auto tmp1 = Rot::rent(N);
  auto tmp2 = Rot::rent(N);
  std::cout << tmp1->size() << std::endl;
  std::cout << tmp1.get() << std::endl;
  std::cout << tmp2->size() << std::endl;
  std::cout << tmp2.get() << std::endl;
}

int main(int argc, char const *argv[]) {
  std::cout << "func1(10)" << std::endl;
  func1(10);
  std::cout << "func1(10)" << std::endl;
  func1(10);
  std::cout << "func2(10)" << std::endl;
  func2(10);
  std::cout << "func1(8)" << std::endl;
  func1(8);
  std::cout << "func1(10)" << std::endl;
  func1(10);
  return 0;
}
```

こんな風に各関数はロータリーからメモリを借りてこれる。

```console
func1(10)
10
0x236c010 # 初確保
func1(10)
10
0x236c010 # 同じのを使う
func2(10)
10
0x236c010 # 一つ目は同じのを使う
10
0x236c0a0 # 既存のメモリは全部貸し出し中だから新しく確保
func1(8)
8
0x236c080 # 引数が違ったら別の領域に確保
func1(10)
10
0x236c010 # ちゃんと最初に確保したのを使ってる
```

のように同じメモリを使い回せている事が分かる。

## 課題

- `vector<Item>`を`unordered_map`にする方が検索が早いはず
- 複数の翻訳単位があるときの静的変数`static Rotary<T> rot`の扱い