web-dev-qa-db-ja.com

オブジェクトをポップしようとしている場合、キューからオブジェクトを「移動」しても大丈夫ですか?

私はcommandsのパーサー(大規模なデータ配列のラッパー)に取り組んでおり、未処理のコマンドが常駐するキューがあります。コマンドが必要な場合は、次のようなコードでクエリします。

boost::optional<command> get_command() {
    if (!has_command()) return boost::optional<command>(nullptr);
    else {
        boost::optional<command> comm(command_feed.front()); //command_feed is declared as a std::queue<command>
        command_feed.pop();
        return comm;
    }
}

問題は、これらのコマンドは、適切な状況下ではメガバイトのサイズになる可能性があり、かなり迅速に解析する必要があることです。私の考えは、次のように移動への転送を最適化できると思いました:

boost::optional<command> get_command() {
    if (!has_command()) return boost::optional<command>(nullptr);
    else {
        boost::optional<command> comm(std::move(command_feed.front())); //command_feed is declared as a std::queue<command>
        command_feed.pop();
        return comm;
    }
}

そして、それはこの特定のケースで機能するようですが、これは適切に維持されているRAIIオブジェクトの汎用ソリューションとして使用できますか、それとも何か他のことをする必要がありますか?

21
Xirema

はい、これは完全に安全です:

_std::queue<T> q;
// add stuff...

T top = std::move(q.front());
q.pop();
_

pop()は、指定された状態を持つqの最初の要素に前提条件がありません。その後、q.front()を使用していないため、そのオブジェクトが無効化されることに対処するため。

いいアイデアですね。

26
Barry

これは、タイプの移動コンストラクターが何をするかによって異なります。それが元のオブジェクトを安全に破壊できる状態のままであれば、すべて順調です。そうでない場合は、問題が発生している可能性があります。前提条件と有効な状態に関するコメントは、定義された型の制約に関するものであることに注意してください標準ライブラリ内。定義する型には、標準ライブラリの型を使用する場合を除いて、これらの制約はありません。したがって、移動コンストラクターを調べて、移動元オブジェクトで実行できることと実行できないことを整理してください。

6
Pete Becker

はい。 _std::queue_のコンテナーテンプレート引数により、pop_front()に含まれる値の状態に前提条件がないことが保証されます。 _std::queue_のデフォルトは_std::deque_であり、保証されています。

私が前の段落で書いたことを確認する限り、あなたは完全に安全です。そのアイテムをキューから削除しようとしています。そのオブジェクトのtake Ownershipであるため、アイテムを移動しない理由はありません。

4
user2296177

オブジェクトを移動すると、オブジェクトが無効な状態になる場合があります。不変条件は保証されなくなりました。煩わしくないキューからそれをポップしても安全です。

  • Std :: move自体は、r値をとるcommルーチンを選択できることをコンパイラに伝える以外に何もしません。

  • 適切に作成されたcommルーチンは、古いオブジェクトから新しいオブジェクトの表現を盗みます。たとえば、ポインタを新しいオブジェクトにコピーし、古いオブジェクトのポインタをゼロにします(これにより、古いオブジェクトのデストラクタは配列を破棄しません)。

  • これを行うためにcommがオーバーロードされていない場合、std :: movを使用してもメリットはありません。

1
Gregg