shared_ptr & weak_ptr conversions

2020-06-01 07:06发布

I am trying to juggle objects using std::shared_ptr and std::weak_ptr. The scenario is something like this:

I have objects of class channel which is derived from a abstract class abstract::channel (with pure virtual functions). I have a container channelContainer (std::vector) containing shared pointers (std::shared_ptr) to channel Objects.

Now, I have a deque (std::deque) containing weak pointers (std::weak_ptr) to each of the object in the channelContainer. Lets name this deque freeChannelQueue.

So lets say:

std::vector<std::shared_ptr<abstract::channel> > channelContainer;
std::deque<std::weak_ptr<abstract::channel > > freeChannelQueue;

//Assuming that both the containers are filled appropriately How do I go about implementeing the below functions?

abstract::channel& get_free_channel() {
  //This should return a free channel object from 'freeChannelQueue' and pop the queue.
}

bool release_channel(abstract::channel& ch) {
 //This should convert 'ch' to a std::weak_ptr (or std::shared_ptr) and push it to   'freeChannelQueue'
}

I am particularly interested in the 'How to convert a reference to an object to a weak pointer?'

3条回答
混吃等死
2楼-- · 2020-06-01 07:17

You cannot

convert a reference to an object to a weak pointer

You can make a weak pointer from a shared pointer, just using assignment = e.g.

std::shared_ptr<abstract::channel> get_free_channel();

then

bool release_channel(std::shared_ptr<abstract::channel> ch)
{
    std::weak_ptr<abstract::channel> weak_ch = ch;
    //...
}

Watch out for lifetimes - will the shared_ptr go before the weak pointers that point to them?

查看更多
趁早两清
3楼-- · 2020-06-01 07:23

I understand your question like this: you have a container to hold all of your channel objects and you have a second container to maintain an order of which channels can be used by your application. You would then like an interface to return a reference to the next free channel for your client, and when the client is finished it releases the channel back to the container.

To get a reference to a channel you can use lock to create a shared_ptr from your weak_ptr and then dereference that (just don't delete the underlying object!). However, I don't see a sensible way to go the other way, you would need to search your channel container for the object that matches and create a weak pointer from the matching shared_ptr again.

I would consider not using weak_ptr and references at all, just stick with shared_ptr. Since you use a deque to maintain which channels are available, you could instead just keep the available shared_ptr's there. If you are happy that your client will always release the channels when finished, you perhaps don't need a container for all the objects, only the deque for the free channels - depends on your overall design.

As others have said, you need to consider the lifetime of your channel objects and how they are used by the client.

查看更多
Melony?
4楼-- · 2020-06-01 07:28

Is this your design? As is, there are some serious channel lifetime issues. For example - if code calls get_free_channel() then your declaration returns them a reference to an object, but they have no way to guarantee it's lifetime encompasses their use. That might not matter depending on what the client code is that you're calling the function from, but you probably want to return a shared_ptr, as in:

std::shared_ptr<abstract::channel> get_free_channel()
{
    // return free channel from 'freeChannelQueue' and pop the queue

    // take a scoped lock on the free queue if necessary

    while (!freeChannelQueue.empty())
    {
         auto p_channel = freeChannelQueue.back();
         freeChannelQueue.pop_back();
         std::shared_ptr<abstract::channel> p = p_channel.lock();
         if (p) return p;
    }

    // freeChannelQueue empty... throw or return nullptr etc..
}

Regarding "release"...

bool release_channel(abstract::channel& ch) {
 //This should convert 'ch' to a std::weak_ptr (or std::shared_ptr) and push it to   'freeChannelQueue'
}

As is, this is only possible if you search the channelContainer to find the object then get your weak_ptr or shared_ptr from there. Again - you should probably change the prototype so it receives a shared_ptr or weak_ptr directly, locks the free queue then pushes the smart pointer on....

All in all, it's hard to give you useful advice without understanding the way your channel lifetime is going to be managed, and how various threads might attempt to use the objects and queues. I hope the above helps a little, even if only in asking a more precise question.

查看更多
登录 后发表回答