2013-07-23 11 views
49

ほとんどすべての投稿で、私はSOを参照して、std::initializer_listを含めて、人々はstd::initializer_listを値渡しがちです。この記事によると:1が渡されたオブジェクトのコピーを作成したい場合なぜ `std :: initializer_list`は値によって渡されるのですか?

http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

1は、値によって渡す必要があります。しかしstd::initializer_listをコピーするのは良い考えではありません。

std::initializer_listをコピーすると、基本となるオブジェクトはコピーされません。 元のイニシャライザリストオブジェクトが終了した の有効期間の後に、基本となる配列が存在することは保証されていません。

、なぜそれのインスタンスは、多くの場合、不要なコピーを作成していないことが保証されconst&は言って、しないことにより、値によって渡されますか?

+1

私が理解しているように、コンパイラは、共通の「値による復帰」イディオムを識別し、代わりに「ムーブ」として最適化します。実際にはその実装にメモリコピーは含まれません。 – MatthewD

+1

@MatthewD私たちはここに戻ることについて話しているわけではありません。 –

答えて

45

安いから値段で渡します。 std::initializer_listは、薄いラッパーであり、一対のポインタとして実装される可能性が最も高いため、コピーは参照渡しの(ほぼ)安価です。さらに、実際にコピーを実行しているわけではありません。ほとんどの場合、引数は一時的なものから構成されているため、への移動は通常です。ただし、これはパフォーマンス上の違いはありません.2つのポインタを移動することは、ポインタをコピーするほど高価です。一方

、コピーの要素にアクセスは、我々は一つの追加の間接参照(参照のこと)を避けるため高速であってもよいです。

+1

'const&'は必ずしもポインタとして実装されているわけではありませんが(私が標準を正しく覚えていれば)、何らかのエイリアスである可能性もあります。 – user1095108

+8

@ user1095108本当に、標準では指定されていません。しかし、現実の世界では、魔法の "エイリアス"タイプはありません。参照は完全に省略されています。ローカルスコープでは代わりに元のエンティティを参照するか、ポインタで置き換えられます。関数*に値*を渡すと(その関数はインライン化されていません)、実際には*保証されてポインタに置き換えられます*。 –

+0

+要素へのアクセスは、通常イテレータで行われます。これらが得られれば、渡された 'const 'を逆参照する必要はありません。 – user1095108

9

おそらく同じ理由で、イテレータはほとんどの場合値渡されます。イテレータのコピーは「安い」と考えられます。 initializer_listの場合、ほとんどのインスタンスは一時的なデストラクタを持つ一時的なものになるため、コンパイラは関数の引数を置く場所に直接コピーを作成することができません。最後に、イテレータのように、呼び出される関数は値を変更したいと思う可能性があります。つまり、constへの参照によって渡された場合、ローカルにコピーする必要があります。

EDIT:

ただ、一般化する:標準ライブラリは、値でイテレータ、initializer_lists、および機能オブジェクトを渡すために優れていることを一般的に仮定します。その結果、あなたが設計したイテレータ、iterator_lists、または機能オブジェクトは安価にコピーすることができます。コピーするのが安価であることをあなたのコードで想定してください。伝統のconstへの参照を使用するときについてのルール、そして時に値を使用するには、おそらくこれを反映するように変更する必要があります。

使用はイテレータ、initializer_listsまたは機能オブジェクト以外のクラス型のためのconstへの参照渡し。それ以外の場合は値渡しを使用します。

+1

しかし、なぜ、 'std :: function <>'インスタンスをコピーするのですか?確かにそれは安くコピーすることはできません。 – user1095108

+1

@ user1095108標準ライブラリは、常にコピーで渡します。だから実装は、それがコピーするのが安くするために必要なことは何でもしなければなりません。 (そして、コピーするのが高価になることを避けるべきです。その中に大きな 'std :: vector'を入れた' std :: function'は良い考えではありません。) –

+0

'std :: function'といえば: 'std :: bind'の結果はお互いに移動でき、移動するとバウンド引数を移動します。私はこれが事実であることを確認するためにデバッグしました。したがって、ベクトルを効率的に動かすことができるので、例えば束縛ベクトルを含む 'std :: function'から移動することは比較的効率的でなければなりません。 – haelix

関連する問題