Home > Software design >  Working with std::unique_ptr and std::queue
Working with std::unique_ptr and std::queue

Time:12-17

Maybe it's my sinuses and that I fact that I just started learning about smart pointers today I'm trying to do the following:

  • Push to the queue
  • Get the element in the front
  • Pop the element (I think it will automatically deque once the address out of scope)

Here is the error

main.cpp:50:25: error: cannot convert ‘std::remove_reference&>::type’ {aka ‘std::unique_ptr’} to ‘std::unique_ptr*’ in assignment
   50 |   inputFrame = std::move(PacketQueue.front());
      |                ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
      |                         |
      |                         std::remove_reference<std::unique_ptr<MyObject::Packet>&>::type {aka std::unique_ptr<MyObject::Packet>}

Here is the code

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

using namespace std;

class MyObject
{
    public:
    struct Packet
    {
        uint8_t message;
        uint8_t index;
    };
    
    void pushToQueue(void);
    void FrontOfQueue(std::unique_ptr<Packet> *inputFrame);
    
    private:
    
    std::queue<std::unique_ptr<Packet>> PacketQueue;
};

void MyObject::pushToQueue(void)
{
    Packet frame;
    
    static int counter = 1;
    frame.message = counter;
    frame.index =counter;
    
    counter  ;
    
    std::unique_ptr<Packet> passthru_ptr = std::make_unique<Packet>(std::move(frame));
    PacketQueue.push(std::move(passthru_ptr));
    
    cout<<"Pushed to queue\n" ;
}

void MyObject::FrontOfQueue(std::unique_ptr<Packet> *inputFrame)
{
  inputFrame = std::move(PacketQueue.front());
}


int main()
{
    cout<<"Hello World\n";
    
    MyObject object;
    
    object.pushToQueue();
    object.pushToQueue();
    
    {
      // Scope 
    std::unique_ptr<MyObject::Packet> *frame;
    
    object.FrontOfQueue(frame); 
    
    cout<< frame << endl;
    
    }
    
    
    {
      // Scope 
    std::unique_ptr<MyObject::Packet> *frame2;
    
    object.FrontOfQueue(frame2); 
    
    cout<< frame2 << endl;
    
    }
    
    

  
    
    return 0;
}

Link to the code (Online Compiler)

CodePudding user response:

If I got your aim correctly, you definitely want

std::unique_ptr<MyObject::Packet> MyObject::FrontOfQueue()
{
  auto rv = std::move(PacketQueue.front());
  PacketQueue.pop();
  return rv;
}
// ...
std::unique_ptr<MyObject::Packet> frame = object.FrontOfQueue(); 

Notice, no raw pointers are used.

I think it will automatically deque once the address out of scope.

This assumption is wrong. Nothing is dequeued until .pop() is called.

CodePudding user response:

Here is my example with some extra logging to show whats going on. includes an introduction of returning const references as well. Live demo : https://onlinegdb.com/P2nFkdMy0

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

//-----------------------------------------------------------------------------
// do NOT use : using namespace std;

//-----------------------------------------------------------------------------

struct Packet
{
    // moved to uint32_t for std::cout reasons.
    // uint8_t is displayed as(special) characters
    std::uint32_t index;
    std::uint32_t message; 
    

    Packet() :
        index{ next_index() },
        message{ index }
    {
        std::cout << "created packet : " << index << "\n";
    }
    
    ~Packet()
    {
        std::cout << "destroyed packet : " << index << "\n";
    }

    // small helper to not have to declare the static variable seperatly
    static std::uint8_t next_index()
    {
        static int counter;
        return counter  ;
    }
};

//-----------------------------------------------------------------------------

class MyObject
{
public:
    void push_packet();
    std::unique_ptr<Packet> pop_packet();

    // this function returns a const reference (observation only)
    // of the packet at the front of the queue
    // while leaving the unique pointer on the queue (no moves needed
    // packet will still be owned by the queue)
    const Packet& front();

private:
    std::queue<std::unique_ptr<Packet>> m_queue;
};

void MyObject::push_packet()
{
    std::cout << "push_packet\n";
    // push a packet 
    m_queue.push(std::make_unique<Packet>());
    std::cout << "push_packet done...\n";
}

std::unique_ptr<Packet> MyObject::pop_packet()
{
    std::unique_ptr<Packet> packet = std::move(m_queue.front());
    m_queue.pop();
    return packet;
}

const Packet& MyObject::front()
{
    return *m_queue.front();
}

//-----------------------------------------------------------------------------

int main()
{
    const std::size_t n_packets = 3ul;

    MyObject object;

    for (std::size_t n = 0; n < n_packets;   n)
    {
        std::cout << "pushing packet\n";
        object.push_packet();
    }

    for (std::size_t n = 0; n < n_packets;   n)
    {
        std::cout << "packet at front : ";
        std::cout << object.front().index << "\n";

        std::cout << "popping front\n";
        auto packet_ptr = object.pop_packet();
        std::cout << "popped packet : " << packet_ptr->index << "\n";
    }

    return 0;
}
  • Related