是否可以从队列中"移动"一个对象,如果你要从中弹出它?

Xir*_*ema 16 c++ boost stl optional c++11

我一直在研究解析器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;
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是,在适当的情况下,这些命令的大小可能是兆字节,并且需要非常快速地解析.我的想法是,我可以优化转移到这样的移动:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

它似乎适用于这种特定情况,但它可以用作任何正确维护的RAII对象的通用解决方案,还是我应该做其他事情?

Bar*_*rry 27

是的,这是非常安全的:

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

T top = std::move(q.front());
q.pop();
Run Code Online (Sandbox Code Playgroud)

pop()q具有指定状态的第一个元素上没有任何先决条件,并且由于您之后没有使用过q.front(),因此不必再处理该对象无效.

听起来好主意!

  • @juanchopanza当然,只要`T`是MoveConstructible即可。 (2认同)

Pet*_*ker 6

这取决于您的类型的移动构造函数.如果它使原始对象处于可以安全销毁的状态,那么一切都很好.如果没有,那么你可能遇到麻烦了.请注意,有关前提条件和有效状态的注释是关于标准库中定义类型的约束.您定义的类型没有这些约束,除非它们使用标准库中的类型.因此,请查看您的移动构造函数,以便根据移动的对象来理清您可以做什么和不能做什么.

  • 如果移动的对象不可破坏,则此移动构造函数/赋值基本上不可用. (5认同)