とはまったく同じコードを使用できるため、unordered_map
型消去を使用して実装されているのではないかと思いました(マシンコードのno-opであるキャストを除く)。つまり、両方の実装は、コードサイズを節約することに基づくことができます。unordered_map<Key, A*>
unordered_map<Key, B*>
unordered_map<Key, void*>
更新:この手法は、一般にシンテンプレートイディオムと呼ばれます(それを指摘してくれた以下のコメント提供者に感謝します)。
アップデート2:ハワード・ヒナントの意見に特に興味があります。彼がこれを読んでくれることを願っています。
だから私はこの小さなテストを書きました:
#include <iostream>
#if BOOST
# include <boost/unordered_map.hpp>
using boost::unordered_map;
#else
# include <unordered_map>
using std::unordered_map;
#endif
struct A { A(int x) : x(x) {} int x; };
struct B { B(int x) : x(x) {} int x; };
int main()
{
#if SMALL
unordered_map<std::string, void*> ma, mb;
#else
unordered_map<std::string, A*> ma;
unordered_map<std::string, B*> mb;
#endif
ma["foo"] = new A(1);
mb["bar"] = new B(2);
std::cout << ((A*) ma["foo"])->x << std::endl;
std::cout << ((B*) mb["bar"])->x << std::endl;
// yes, it leaks.
}
そして、さまざまな設定でコンパイルされた出力のサイズを決定しました。
#!/bin/sh
for BOOST in 0 1 ; do
for OPT in 2 3 s ; do
for SMALL in 0 1 ; do
clang++ -stdlib=libc++ -O${OPT} -DSMALL=${SMALL} -DBOOST=${BOOST} map_test.cpp -o map_test
strip map_test
SIZE=$(echo "scale=1;$(stat -f "%z" map_test)/1024" | bc)
echo boost=$BOOST opt=$OPT small=$SMALL size=${SIZE}K
done
done
done
私が試したすべての設定で、の多くの内部コードがunordered_map
2回インスタンス化されているようです。
With Clang and libc++:
| -O2 | -O3 | -Os
-DSMALL=0 | 24.7K | 23.5K | 28.2K
-DSMALL=1 | 17.9K | 17.2K | 19.8K
With Clang and Boost:
| -O2 | -O3 | -Os
-DSMALL=0 | 23.9K | 23.9K | 32.5K
-DSMALL=1 | 17.4K | 17.4K | 22.3K
With GCC and Boost:
| -O2 | -O3 | -Os
-DSMALL=0 | 21.8K | 21.8K | 35.5K
-DSMALL=1 | 16.4K | 16.4K | 26.2K
(AppleのXcodeのコンパイラを使用)
ここで質問になります。実装者がこの単純な最適化を省略することを選択したために、説得力のある技術的な理由がありますか?
また、なぜ地獄-Os
は宣伝されているものとは正反対の効果なのですか?
アップデート3:
Nicol Bolasが提案したように、私はshared_ptr<void/A/B>
裸のポインター(で作成され、make_shared
でキャストされたstatic_pointer_cast
)の代わりに測定を繰り返しました。結果の傾向は同じです。
With Clang and libc++:
| -O2 | -O3 | -Os
-DSMALL=0 | 27.9K | 26.7K | 30.9K
-DSMALL=1 | 25.0K | 20.3K | 26.8K
With Clang and Boost:
| -O2 | -O3 | -Os
-DSMALL=0 | 35.3K | 34.3K | 43.1K
-DSMALL=1 | 27.8K | 26.8K | 32.6K