pop_back()
戻り値がないのはなぜですか?私はこれについてグーグルで調べたところ、より効率的であることがわかりました。これが標準でそうする唯一の理由ですか?
8 に答える
効率性はほとんど (またはまったく) 関係ありません。
このデザインは、90 年代に発表された Tom Cargill による重要な論文の成果であり、当時かなりの数の眉をひそめていました。IIRC の中で、Cargill は、例外セーフなスタック ポップ機能を設計することは不可能であることを示しました。
最後のオブジェクトのインスタンスをコピーすると例外がスローされる可能性があるという事実に関連する何かがあると思います。pop_back() がオブジェクトをコンテナから削除したため、そうすると、オブジェクトが失われます。数行のコードで改善します。
std::vector<AnyClass> holds = {...} ;
try {
const AnyClass result = holds.pop_back(); // The copy Ctor throw here!
} catch (...)
{
// Last value lost here.
}
これは、コマンドとクエリの分離の原則によるものです。
効率は一つのことです。pop_back()
要素を返さないもう 1 つの理由は、例外の安全性です。
関数pop()
が値を返し、コピー コンストラクターによって例外がスローされた場合、コンテナーが を呼び出す前と同じ状態であることを保証できない場合がありますpop()
。
例外に関する詳細は、Herb Sutters の本を参照してください。このトピックはここでカバーされていると思います。しかし、よくわかりません。
その理由は、例外の安全性ほど効率的ではありません。コンテナー クラスは、あらゆる種類のオブジェクトを格納するために使用できます。オブジェクトの値を返すにはコピー構築が含まれるため、関数がコンテナからオブジェクトを削除した後にオブジェクトを返す場合、例外セーフな方法で pop_back() を実装することは不可能です。
これは、GNU C++ 標準ライブラリでの vector::pop_back() の実際の実装です。
void
pop_back()
{
--this->_M_impl._M_finish;
this->_M_impl.destroy(this->_M_impl._M_finish);
}
最後に最後の要素を返すと、次のようになります。
value_type
pop_back()
{
value_type save = back();
--this->_M_impl._M_finish;
this->_M_impl.destroy(this->_M_impl._M_finish);
return save;
}
これには、save = back()
ステートメントとオブジェクトのコピーを返すときの 2 つのコピー構成が含まれます。要素がコンテナーから破棄された後、return 式が例外をスローしないという保証はありません。
さて、いくつの理由が必要ですか?
これにより、コンテナからオブジェクトを削除したいだけの場合に、コストがかかる可能性のあるオブジェクトのコピーを回避できます。C++ には、必要のないものにはお金を払わないという哲学があります。
なぜ値を返すのでしょうか? 値をポップする前に、いつでも値にアクセスできますpop_back
。この機能を提供する必要はありません。