Will
Will

Reputation: 21

std::move() with priority_queue.top()

I am new to smart pointers. Recently I started working on some parallel simulations and I thought shared_ptr will help prevent memory leaks. I heard that incrementing the number of instances can cause non-negligible extra time overhead, so I hope to avoid doing that.

In my code I was using a priority_queue to manage the events in the simulation. To make sure I understood what happens with shared_ptr in these containers I did some tests:

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';

Using the above two different ways to get the pointer from the priority_queue, I was expecting the second way to return 1 in use_count(). However I saw a value of 2, whether or not I used std::move() to get the top pointer in the queue. I compiled with g++ -std=c++0x [FileName]

Can someone point out where I was doing wrong? Do both the methods above indicate I will still have extra time over head?

Upvotes: 1

Views: 925

Answers (4)

jswl
jswl

Reputation: 82

This should give you use_count of 1.

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

And, this should give you use_count of 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';

}

Upvotes: 1

Praetorian
Praetorian

Reputation: 109109

priority_queue::top returns a const& to the top element.

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

The line above creates a new shared_ptr which now shares ownership of the top element with the shared_ptr that's in the priority_queue, so use_count is 2.

std::move doesn't affect the result because moving a const object will call the shared_ptr copy constructor, same as the line above.

To keep use_count at 1, use

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

Upvotes: 4

Jive Dadson
Jive Dadson

Reputation: 17026

Move does not delete the object pointed to. It leaves it in some "valid but unspecified state." (Their words, not mine.) Or at least it will if Base and Derived play by the rules. If rather than Derived, you had used std::strings, they would probably be left as empty strings, but it would be legal for the implementation to leave them as "Surprise! Moved out.".

Upvotes: 0

3CxEZiVlQ
3CxEZiVlQ

Reputation: 38341

queue.top() returns const_reference, const can not be moved. Const returned since elements in a priority queue are not allowed to be modified, it can break an order in a priority queue.

Upvotes: 0

Related Questions