これは具体的なことではありませんswap
が、低レベルの最適化は問題にならない可能性があることを示す例です。とにかく、コンパイラはしばしばそれを理解します。
もちろん、これはコンパイラが非常に幸運である私のお気に入りの例ですが、とにかく、コンパイラが愚かで、生成されたコードをいくつかの簡単なトリックで簡単に改善できると想定すべきではありません。
私のテストコードは - std::string を構築してコピーします。
std::string whatever = "abcdefgh";
std::string whatever2 = whatever;
最初のコンストラクタは次のようになります
basic_string(const value_type* _String,
const allocator_type& _Allocator = allocator_type() ) : _Parent(_Allocator)
{
const size_type _StringSize = traits_type::length(_String);
if (_MySmallStringCapacity < _StringSize)
{
_AllocateAndCopy(_String, _StringSize);
}
else
{
traits_type::copy(_MySmallString._Buffer, _String, _StringSize);
_SetSmallStringCapacity();
_SetSize(_StringSize);
}
}
生成されたコードは
std::string whatever = "abcdefgh";
000000013FCC30C3 mov rdx,qword ptr [string "abcdefgh" (13FD07498h)]
000000013FCC30CA mov qword ptr [whatever],rdx
000000013FCC30D2 mov byte ptr [rsp+347h],0
000000013FCC30DA mov qword ptr [rsp+348h],8
000000013FCC30E6 mov byte ptr [rsp+338h],0
これは、文字列全体の 1 つのレジスタ コピーに最適化されます (適合するように慎重に選択されます) traits_type::copy
。memcpy
また、コンパイラは への呼び出しをstrlen
コンパイル時の に変換します8
。
次に、それを新しい文字列にコピーします。コピーコンストラクタは次のようになります
basic_string(const basic_string& _String)
: _Parent(std::allocator_traits<allocator_type>::select_on_container_copy_construction(_String._MyAllocator))
{
if (_MySmallStringCapacity < _String.size())
{
_AllocateAndCopy(_String);
}
else
{
traits_type::copy(_MySmallString._Buffer, _String.data(), _String.size());
_SetSmallStringCapacity();
_SetSize(_String.size());
}
}
たった 4 つの機械語命令になります。
std::string whatever2 = whatever;
000000013FCC30EE mov qword ptr [whatever2],rdx
000000013FCC30F6 mov byte ptr [rsp+6CFh],0
000000013FCC30FE mov qword ptr [rsp+6D0h],8
000000013FCC310A mov byte ptr [rsp+6C0h],0
オプティマイザは、char
がまだ登録されrdx
ていること、および文字列の長さが同じでなければならないことを記憶していることに注意してください8
。
このようなものを見た後、私は自分のコンパイラを信頼し、少しいじってコードを改善しようとするのを避けたいと思っています。プロファイリングで予期しないボトルネックが見つからない限り、これは役に立ちません。
(MSVC 10 と私の std::string 実装をフィーチャー)