I have situation like this
struct Foo
{
Foo(int x, int y) : x(x), y(y)
{
}
int x, y;
};
class Bar
{
public:
typedef std::shared_ptr<const Foo> ConstFooPtr;
typedef std::shared_ptr<Foo> FooPtr;
Bar(int index = 0, FooPtr ptr = FooPtr()) : index_(index), ptr_(ptr)
{
}
private:
ConstFooPtr ptr_;
int index_;
};
I want to produce Bar and 2 methods comes to my mind
Bar::FooPtr ptr(new Foo(1, 2)); //1
auto ptr2 = std::make_shared<Bar::FooPtr::element_type>(42, 13); //2
auto bar = Bar(0, ptr);
The first one is pretty general, because if I will change the type of FooPtr
perhaps I will not have to chage this code. But it uses new
which is bad I guess.
Second doesn't use new
, but it assumes that it is shared_ptr
which is not general also.
Is there any method to make it work and be general? Or maybe I should never take some ptrs in constructor?
(I store ptr
to const Foo
because I will make copies of Bar
and change index_
, but data
in ptr_
will be the same - You can assume that Foo
is something big with some containers)
Just roll your own version of make_shared
and put it as a static member of Bar
:
template<typename... Args>
static FooPtr make_shared_foo(Args... args)
{
return ::std::make_shared<Foo>(::std::forward<Args>(args)...);
}
This way you can make you pointer like so:
auto ptr3 = Bar::make_shared_foo(3,14159);
Of course, nothing prevents you from taking this to its ultimate version:
Bar(int index = 0) : index_(index), ptr_(FooPtr())
{ }
template<typename... Args>
Bar(int index, Args... args)
: index_(index)
, ptr_(new Foo(::std::forward<Args>(args)...))
{ }
Which just allows you to pass your arguments to the constructor to Bar
which will then forward them to create a pointer to Foo
for its own consumption.