std::function<void(int&)>
C++11の はどのような魔法sizeof = 32
ですか? 関数参照をポインターとして保存すると、コストはわずかになります8 bytes
(64 ビット マシン上)。
2 に答える
std::function<Signature>
興味深いのは、オブジェクトのサイズと割り当ての間のトレードオフです。小さな関数オブジェクトの場合、割り当てを避けることが望ましいです。一方で、そうするとオブジェクトのサイズが大きくなります。小さな関数の最適化が有効であり、実際にオブジェクトを呼び出すときにオーバーヘッドが発生しないようにするには、オブジェクトのサイズは、少なくとも 2 つのポインターと単純な関数オブジェクトを格納するためのメモリが必要です。32 バイトのサイズはまさにこれのようです (システムでsizeof(T*)
は 8)。
つまり、std::function<Signature>
オブジェクトは内部的に継承階層を格納します。基本クラスは、呼び出されるインターフェイスを提供し、呼び出しインターフェイス (さらに、おそらくいくつかのclone()
機能) を実装するテンプレート化された派生クラスに委譲します。サイズが最適化された実装では、関数オブジェクトはベースへのポインターを保持するだけですが、割り当てを回避するために、オブジェクト全体を割り当ててこのオブジェクトを指す内部ストレージを確保します (内部ポインターは、実際に呼び出すときに条件を回避します関数オブジェクト)。オブジェクトに必要なメモリは、仮想関数ポインタと、std::function<Signature>
オブジェクトが初期化される実際の関数オブジェクトのデータです。メンバー関数をオブジェクトに対応させるには、さらに 2 つの単語を使用するのが妥当なようです。
std::function
任意の呼び出し可能なオブジェクトから構築できるため、実際に魔法です! たとえ表面上はささいvoid(int&)
な署名を保持していても、それはあなたのためにどんな量の状態でも喜んで保存します。
このマジックには確かに代償が伴います。これは通常、ある種の型消去 (つまり、動的割り当てと仮想ディスパッチ) を内部的に使用します。auto
詳細はさまざまですが、結果として得られるオブジェクトは確かに「重い」ものです。そのため、可能であればテンプレートを使用してオブジェクトを避ける必要があります。