Reputation: 2775
I have several producers
and one consumer
which hold a queue
, when producer produce an object, it wrap it into a shared_ptr
and send to consumer queue for processing, because different producer may produce different type of object, so the queue is defined as
struct FrameHeader {
int data_type;
};
class Frame {
private:
std::shared_ptr<FrameHeader> header;
std::shared_ptr<void> body;
public:
Frame(const std::shared_ptr<FrameHeader> header, const std::shared_ptr<void> body);
std::shared_ptr<FrameHeader> get_header();
std::shared_ptr<void> get_body();
};
std::deque<std::shared_ptr<Frame>> data_q;
when I pop an Frame
from data_q
, I look into to data_type
field in header
to decide which object I should cast the body
into
May question is with c++17
I learnt there is a new feature called std::any
that I can use to hold any object, should I use any
in place of shared_ptr<void>
like this?
class Frame {
private:
std::shared_ptr<FrameHeader> header;
any body;
public:
Frame(const std::shared_ptr<FrameHeader> header, const std::shared_ptr<void> body);
std::shared_ptr<FrameHeader> get_header();
any get_body();
};
...
auto real_obj_ptr = any_cast<shared_ptr<RealClass>>(frame.get_body());
Also if there is better way of handling this situation?
Upvotes: 3
Views: 3042
Reputation: 6604
The std::any
doesn't substitute the std::shared_ptr
and vice versa: they have different purposes.
Shared pointer is used whenever you need to keep track over the life time of the object, and delete it when the last reference is destroyed. That is obvious. The std::any
doesn't do that. On the other hand std::any
can keep the reference to any object and is safer than any tricks with void*
(stared_ptr<void>
is one of them). Technically you may combine both:
std::any a = std::make_shared<int>(42);
std::cout << *std::any_cast<std::shared_ptr<int>>(a);
This approach has a drawback that std::any
allocates the objects on heap, because it cannot know in advance the maximum size of the type being stored. If you can limit the number of stored types, you may use a more efficient and safer pattern: std::variant
.
Actually there are plenty of patterns that can be used, and they have their own pros and cons. For example, you may use a common base class together with std::shared_ptr<Base>
. You may use double dispatching for safer type erasure. Nobody knows your task except of you, so try to give a detailed description of the problems you experience.
Upvotes: 5