11

で一連のunique_ptrインスタンスを維持していpriority_queueます。ある時点で、最初の要素を取得してキューから削除したいと考えています。ただし、これは常にコンパイラ エラーを生成します。以下のサンプルコードを参照してください。

int main ()
{
  std::priority_queue<std::unique_ptr<int>> queue;
  queue.push(std::unique_ptr<int>(new int(42)));

  std::unique_ptr<int> myInt = std::move(queue.top());
  return 1;
}

これにより、次のコンパイラ エラーが発生します (gcc 4.8.0)。

uptrtest.cpp: In function ‘int main()’: uptrtest.cpp:6:53: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = int; _Dp = std::default_delete<int>]’    std::unique_ptr<int> myInt = std::move(queue.top());
                                                     ^ In file included from /usr/include/c++/4.8/memory:81:0,
                 from uptrtest.cpp:1: /usr/include/c++/4.8/bits/unique_ptr.h:273:7: error: declared here
       unique_ptr(const unique_ptr&) = delete;
       ^

この質問queueのように使用するコードを変更すると、問題が修正され、コードは問題なくコンパイルされます。

unique_ptrs を aに保持する方法はありませんか、priority_queueそれとも何か不足していますか?

4

5 に答える 5

11

std::priority_queue::top()const 参照を返すため、移動できません。のパブリック インターフェイスをpriority_queue見ると、移動できる非 const 参照を取得するメソッドはありません (これは必須でunique_ptrあり、コピー コンストラクターはありません)。

解決策:それらをコピーできるようにするには(移動するだけでなく)にunique_ptr置き換えます。shared_ptr

もちろん、別の種類のコンテナーを使用することもできます (ただしpriority_queue、最初から選択した場合、これはおそらく受け入れられません)。

「保護されたメンバーのハック」を使用して、保護されたメンバーc(基になるコンテナー) にアクセスすることもできますが、お勧めしません。これはかなり汚れており、おそらく UB です。

于 2013-05-21T02:13:45.610 に答える
9

同意します、これは信じられないほど迷惑です。std::move要素をキューに入れることができるのに、それらを移動する方法がないのはなぜですか? 元のコピーはもうないので、top()andを実行するときは非 const オブジェクトが必要pop()です。

解決策:両方を一度に実行std::priority_queueするメソッドを追加して、 extendを追加します。pop_top()これにより、キューの順序が保持されます。ただし、c ++ 11に依存します。次の実装は、gcc コンパイラでのみ機能します。

template<typename _Tp, typename _Sequence = std::vector<_Tp>,
    typename _Compare = std::less<typename _Sequence::value_type> >
class priority_queue: std::priority_queue<_Tp, _Sequence, _Compare> {
public:
    typedef typename _Sequence::value_type value_type;
public:

#if __cplusplus < 201103L
explicit
priority_queue(const _Compare& __x = _Compare(),
        const _Sequence& __s = _Sequence()) : 
        std::priority_queue(__x, __s) {}
#else
explicit 
priority_queue(const _Compare& __x, const _Sequence& __s) :
        std::priority_queue<_Tp, _Sequence, _Compare>(__x, __s) {}

explicit 
priority_queue(const _Compare& __x = _Compare(), _Sequence&& __s =
        _Sequence()) :
        std::priority_queue<_Tp, _Sequence, _Compare>(__x, std::move(__s)) {}
#endif

using std::priority_queue<_Tp, _Sequence, _Compare>::empty;
using std::priority_queue<_Tp, _Sequence, _Compare>::size;
using std::priority_queue<_Tp, _Sequence, _Compare>::top;
using std::priority_queue<_Tp, _Sequence, _Compare>::push;
using std::priority_queue<_Tp, _Sequence, _Compare>::pop;

#if __cplusplus >= 201103L

using std::priority_queue<_Tp, _Sequence, _Compare>::emplace;
using std::priority_queue<_Tp, _Sequence, _Compare>::swap;

/**
 *  @brief  Removes and returns the first element.
 */
value_type pop_top() {
    __glibcxx_requires_nonempty();

    // arrange so that back contains desired
    std::pop_heap(this->c.begin(), this->c.end(), this->comp);
    value_type top = std::move(this->c.back());
    this->c.pop_back();
    return top;
}

#endif

};
于 2014-11-18T17:24:24.113 に答える