std::shared_ptr and initializer lists
Try this:
auto ptr = std::make_shared<Func>(std::initializer_list<std::string>{"foo", "bar", "baz"});
Clang is not willing to deduce the type of {"foo", "bar", "baz"}
. I'm currently not sure whether that is the way the language is supposed to work, or if we're looking at a compiler bug.
std::initializer_list and std::make_shared: too many arguments ... 3 expected 0 provided
{1,2,3}
can be multiple things, and make_shared has no possibility of knowing what it is at the time parameter pack is expanded.
If you don't want to state the long std::initializer_list<int>{1,2,3}
explicitly, the easiest solutions would be:
a. shortening the type's name: using ints=std::initializer_list<int>;
b. wrapping the call:
auto make_shared_S(int x, double y, std::initializer_list<int> l)
{
return std::make_shared<S>(x, y, l);
}
Demo: https://godbolt.org/z/WErz87Ks4
Casting shared_ptr in initializer list
A shared_ptr<Derived>
can be converted to a shared_ptr<Base>
, but it is not a shared_ptr<Base>
.
In other words, this compiles:
std::shared_ptr<Derived> pd;
std::shared_ptr<Base> pb = pd;
But this does not:
std::shared_ptr<Base>& pb = pd;
But this does, because const references can bind to temporaries and this will implicitly perform a conversion:
std::shared_ptr<Base> const& pb = pd;
The problem is that you're taking non-const lvalue references in your constructors. You should either take const lvalue references or just take them by value.
How to initialize a shared pointer in the initialization list of a constructor?
Add a constructor explicit Bar::Bar(const callback&)
. explicit
will prevent mistakes related to automatic conversion. Then you can initialize a shared_ptr<Bar>
like this:
Foo::Foo(const callback& cb)
: m_ptr(std::make_shared<Bar>(cb))
See documentation for make_shared
here.
std::make_shared with std::initializer_list
For this to work, you need to create a custom make_shared_from_list
, as make_shared
does not support non-explicit initializer lists. The reason is described well by @brian.
I would use a traits class to map a type T
to the type of initializer list.
template<class>struct list_init{};// sfinae support
template<> struct list_init<Derived>{using type=std::pair<int, std::shared_ptr<Base>>;};
template<class T>using list_init_t=typename list_init<T>::type;
template<class T>
std::shared_ptr<T> make_shared_from_list( std::initializer_list<list_init_t<T>> list ){
return std::make_shared<T>( std::move(list) );
}
or something like that.
Alternatively, "cast" the {...}
to the initializer_list<blah>
directly (not a cast, but rather a construction) may work.
In theory, sufficient reflection metaprogramming support would allow shared_ptr
to do this without the traits class, bit that is pretty far down the pipe.
Shared argument in constructor initializer list
Actually, I thought of a better solution. Create the shared_ptr
, then delegate to a private constructor that will use it to construct _a
and _b
. (Credit to Zan Lynx for suggesting the use of a function parameter as temporary storage.)
class Foo {
public:
Foo(): Foo(std::make_shared<SomeClass>()) {}
private:
Foo(std::shared_ptr<SomeClass> ptr): _a(ptr), _b(ptr) {}
A _a;
B _b;
};
Conditionally make shared_ptr in initializer list null
b(true ? std::make_shared<Bar>() : nullptr)
shared pointer in constructor initializer list
The segmentation fault for accessing a unassigned shared_ptr<>
is perfectly normal, as you are essentially dereferencing null
.
The interesting bit is why your first test did not crash.
int_ptr my_int_ptr();
This line of code does not do what you think it does. You are forward declaring a function called my_int_ptr
that returns an int_ptr
, not declaring a default-initialized instance of int_ptr
.
Related Topics
Local Type as Template Arguments in C++
Reading a Matrix Txt File and Storing as an Array
Equivalent of Console.Readline() in C++
Using Std::Make_Unique with a Custom Deleter
How to Read from Memory Just Like from a File Using iOStream
Insert into an Stl Queue Using Std::Copy
C++ Delete Does Not Free All Memory (Windows)
Random Number Generator - Why Seed Every Time
How to Increase Error Limit in Visual Studio
Bitwise Operations on Vector<Bool>
How to Find Out Cl.Exe's Built-In MACros
Any Good Solutions for C++ String Code Point and Code Unit
Can Pointers Be of Different Sizes
Why Does C++11 Not Support Anonymous Structs, While C11 Does
C++. Error: Void Is Not a Pointer-To-Object Type
What's the Difference Between Getline and Std::Istream::Operator>>()
Why Does (I|O)Fstream Take a Const Char* Parameter for a File Name