最小的工作示例。

#include <cassert>
#include <list>
#include <queue>
//#define USE_PQ

struct MyClass
{
    const char* str;
    MyClass(const char* _str) : str(_str) {}
    MyClass(MyClass&& src) { str = src.str; src.str = nullptr; }
    MyClass(const MyClass&) = delete;
};

struct cmp_func
{
    bool operator() (const MyClass&, const MyClass&) const
    {
        return true;
    }
};

typedef std::priority_queue<MyClass, std::vector<MyClass>, cmp_func> pq_type;

#ifdef USE_PQ
MyClass remove_front(pq_type& l)
{
    MyClass moved = std::move(l.top());
    // error from the above line:
    // use of deleted function ‘MyClass::MyClass(const MyClass&)’
    l.pop();
    return std::move(moved);
}
#else
MyClass remove_front(std::list<MyClass>& l)
{
    MyClass moved = std::move(l.front());
    l.erase(l.begin());
    return std::move(moved);
}
#endif

int main()
{
    const char* hello_str = "Hello World!";
    MyClass first(hello_str);
#ifdef USE_PQ
    pq_type l;
    l.push(std::move(first));
    MyClass moved = remove_front(l);
#else
    std::list<MyClass> l;
    l.push_back(std::move(first));
    MyClass moved = remove_front(l);
#endif
    assert(moved.str);
    assert(!first.str);
    return 0;
}

所以这可行。现在从第4行删除注释符号,它说需要复制构造函数(删除了我的)。此外,它错过了operator=。问题:
  • 这有什么区别?
  • 问题可以解决吗?如果是,怎么办,如果不是,为什么不呢?

  • 注意:您也可以使用boost的priority_queue作为答案,但是我也遇到了同样的错误。

    最佳答案

    这似乎是std::priority_queue<T>设计的疏忽。似乎没有一种方法可以将元素直接移出(而不是复制)。问题在于top()返回const T&,因此无法绑定(bind)到T&&。而且pop()返回void,因此您也无法从中获得它。

    但是,有一种解决方法。保证优先级队列中的对象实际上不是const一样好。它们是普通的对象,队列只是不能对它们进行可变的访问。因此,这样做是完全合法的:

    MyClass moved = std::move(const_cast<MyClass&>(l.top()));
    l.pop();
    

    正如@DyP在注释中指出的那样,您应该确保从对象移出仍然可以传递到队列的比较器。而且我相信,为了保留队列的先决条件,它必须与以前进行比较(这几乎是不可能实现的)。

    因此,您应该将cast & top()pop()调用封装在一个函数中,并确保在此之间不对队列进行任何修改。如果这样做,则可以合理确定比较器将不会在移出的对象上被调用。

    当然,这种功能应该有充分的文档证明。

    请注意,每当为类提供自定义复制/move 构造函数时,都应提供相应的复制/move 赋值运算符(否则,该类的行为可能会不一致)。因此,只需给您的类(class)一个已删除的拷贝分配运算符和一个适当的 move 分配运算符即可。

    (注意:是的,在某些情况下,您需要一个可 move 构造的类,而不是可 move 分配的类,但这种情况极为罕见(一旦找到它们,您就会知道它们)。作为经验法则,始终同时提供ctor和工作分配op)

    关于c++ - 在C++ 11中移出std priority_queue的元素,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/20149471/

    10-10 21:29