【问题标题】:std::move() with priority_queue.top()std::move() 与 priority_queue.top()
【发布时间】:2018-03-08 03:40:42
【问题描述】:

我是智能指针的新手。最近我开始进行一些并行模拟,我认为shared_ptr 将有助于防止内存泄漏。我听说增加实例数量会导致不可忽略的额外时间开销,所以我希望避免这样做。

在我的代码中,我使用 priority_queue 来管理模拟中的事件。为了确保我理解这些容器中的 shared_ptr 会发生什么,我做了一些测试:

std::priority_queue<std::shared_ptr<Base>> queue;
queue.push(std::make_shared<Derived>());
std::shared_ptr<Base> p = queue.top();
//std::shared_ptr<Base> p = std::move(queue.top());

std::cout << "Created a shared Derived (as a pointer to Base)\n"
          << "  p.get() = " << p.get()
          << ", p.use_count() = " << p.use_count() << '\n';

使用上述两种不同的方法从priority_queue 中获取指针,我期待第二种方法在use_count() 中返回1。但是,无论我是否使用 std::move() 来获取队列中的顶部指针,我都看到了 2 的值。我用g++ -std=c++0x [FileName]编译

谁能指出我做错了什么?以上两种方法是否都表明我还有额外的时间?

【问题讨论】:

  • 可能与top returns 是const&amp; 的事实有关。此外,您可能不想 move top 的结果,因为 queue 仍然认为它是有效的。
  • 您是否费心测量增加shared_ptr 引用计数是否真的是您的瓶颈,然后再跳过去避免它?
  • 您是否考虑过使用std::unique_ptr?谁共享队列中的对象?
  • 老实说,我认为这不会大幅增加总运行时间。不过我还是很好奇。
  • 啊,纳米,我刚刚看到你不能把unique_ptr 放在priority_queue 中...

标签: c++ c++11 shared-ptr move


【解决方案1】:

priority_queue::topconst&amp; 返回到顶部元素。

std::shared_ptr<Base> p = queue.top();

上面的行创建了一个新的shared_ptr,它现在与priority_queue 中的shared_ptr 共享顶部元素的所有权,所以use_count 是2。

std::move 不影响结果,因为moving a const object 将调用shared_ptr 复制构造函数,与上面的行相同。

要将use_count 保持为 1,请使用

std::shared_ptr<Base> const& p = queue.top();

【讨论】:

  • 没有引用会破坏智能指针的点吗?它不能在不同的范围内使用,如果 queue.top() 被更改,它就会变得悬空。真的比直接使用queue.top()更有用吗?
  • @Galik 取决于您对参考的操作。也许 OP 想要对顶部元素做一些事情,那么与 queue.top() 相比,p 的输入要少得多。当然,您可以存储引用、弹出队列并让自己有一个悬空引用,但引用shared_ptr 绝不意味着您总是会陷入这种情况。基本上,除非您想要共享所有权的第二个对象,否则请使用引用。
  • 我想我只是假设 OP 在他 pop() 排在队列的顶部之后想把它拿出来发送到其他地方。但我们真的不知道它会发生什么。
【解决方案2】:

这应该给你 1 的 use_count。

const std::shared_ptr<Base>& p = queue.top();

而且,这应该给你 use_count 2。

std::shared_ptr<Base> p = queue.top();

_

#include <iostream>
#include <memory>
#include <queue>

using namespace std;

class Base
{
    public:

    Base() {}

    virtual void print()
    {
        cout << "Base" << endl;
    }
};

class Derived
:
    public Base
{
    public:
    Derived() {}

    void print()
    {
        cout << "Derived" << endl;
    }
};


int main()
{

  std::priority_queue<std::shared_ptr<Base>> queue;
  queue.push(std::make_shared<Derived>());
  const std::shared_ptr<Base>& p = queue.top();
  //std::shared_ptr<Base> p = std::move(queue.top());

  std::cout << "Created a shared Derived (as a pointer to Base)\n"
            << "  p.get() = " << p.get()
                      << ", p.use_count() = " << p.use_count() << '\n';

}

【讨论】:

    【解决方案3】:

    queue.top() 返回const_reference,const 不能移动。由于不允许修改优先级队列中的元素,因此返回 const,它可能会破坏优先级队列中的顺序。

    【讨论】:

      【解决方案4】:

      移动不会删除指向的对象。它使其处于某种“有效但未指定的状态”。 (他们的话,不是我的话。)或者至少如果 Base 和 Derived 遵守规则的话。如果您使用的是 std::strings 而不是 Derived,则它们可能会保留为空字符串,但实现将它们保留为“惊喜!移出。”是合法的。

      【讨论】:

      • 上例中没有发生任何动作
      • 被注释掉了。
      • 不,我的意思是即使您取消注释,也没有移动构造,因为 top 返回 const&amp;
      猜你喜欢
      • 2016-07-08
      • 1970-01-01
      • 2015-05-03
      • 1970-01-01
      • 2015-06-21
      • 1970-01-01
      • 2014-02-16
      • 1970-01-01
      相关资源
      最近更新 更多