Initializing Container of Unique_Ptrs from Initializer List Fails with Gcc 4.7

Initializing container of unique_ptrs from initializer list fails with GCC 4.7

unique_ptr's constructor is explicit. So you can't create one implicitly with from new string{"foo"}. It needs to be something like unique_ptr<string>{ new string{"foo"} }.

Which leads us to this

// not good
vector<unique_ptr<string>> vs {
unique_ptr<string>{ new string{"Doug"} },
unique_ptr<string>{ new string{"Adams"} }
};

However it may leak if one of the constructors fails. It's safer to use make_unique:

// does not work
vector<unique_ptr<string>> vs {
make_unique<string>("Doug"),
make_unique<string>("Adams")
};

But... initializer_lists always perform copies, and unique_ptrs are not copyable. This is something really annoying about initializer lists. You can hack around it, or fallback to initialization with calls to emplace_back.

If you're actually managing strings with smart pointers and it's not just for the example, then you can do even better: just make a vector<string>. The std::string already handles the resources it uses.

How to initialize a container of noncopyable with initializer list?

You can't move objects out of initializer lists, since they only allow const access to their members. As such, you can't use initializer lists and move constructors; they can only be copied.

Moving unique_ptr in the declaration of a vector

When you do

vector<unique_ptr<int>> v2 {move(i1), move(i2), move(i3)};

you are not actually moving directly into the vector v2. Instead the compiler will create a std::initializer_list of the moved unique pointers, and pass that list object to the std::vector constructor which will then attempt to copy the elements from the initializer list.

Unfortunately I know of no way to solve the problem, of using the intermediate initializer list to initialize a vector of unique pointers.

How to fix vector of objects that have unique_ptr

The root cause of the error I was getting is due to use of unique_ptr inside the object that is used in intializer list. Similar to vector of simple unique_ptr (as in here Initializing container of unique_ptrs from initializer list fails with GCC 4.7 ) an object that also has unique_ptr in its data model can also NOT be used in initializer list.

Similar to the other link, cause is same; initializer list always performs copies and unique_ptr cannot be copied. So we have to use emplace_back/push_back.

So even with constructor in place the following solution works

struct Container
{
struct Nested{
std::unique_ptr<Container> node;

Nested(): node(nullptr) {}
Nested(std::unique_ptr<Container> t) : node(std::move(t)) {}
};

std::vector<Nested> edges;
};

typedef std::unique_ptr<Container> UCont;
typedef Container::Nested Nested;

int main()
{
auto v = std::vector<Nested>{3};
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
v.push_back(std::move(Nested(std::move(std::unique_ptr<Container>(new Container{})))));
std::unique_ptr<Container> object = UCont(new Container { std::move(v) });

}

How do you initialize (through initializer lists) a multidimensional std::array in C++11?

Try to add one more pair {} to ensure we're initializing the internal C array.

std::array<std::array<int, 2>, 2> shape = {{ {1, 1},
{1, 1} }};

Or just drop all the brackets.

std::array<std::array<int, 2>, 2> shape = { 1, 1,
1, 1 };

Meaning of error converting brace enclosed initializer list to type?

The correct syntax is:

timed_mutex() : _M_mutex({__GTHREAD_MUTEX_INIT}) { }  // i.e. _M_mutex({{0}})

However that feature is available only with C++11. Demo.

For older compilers, you can't use initializer list with constructor.

The reason for having 2 {} is that, pthread_mutex_t is a union defined as shown here. Which contains, a struct, char[24], long int; thus naturally the initialization syntax would differ.

Update:
When I tried to compile <mutex> header in a test file, it gives following error:

/usr/include/c++/4.6/bits/c++0x_warning.h:32:2: error: #error This
file requires compiler and library support for the upcoming ISO C++
standard, C++0x. This support is currently experimental, and must be
enabled with the -std=c++0x or -std=gnu++0x
compiler options.

Quite possibly the particular file follows the initializer syntax of C++11.

Can I list-initialize a vector of move-only type?

The synopsis of <initializer_list> in 18.9 makes it reasonably clear that elements of an initializer list are always passed via const-reference. Unfortunately, there does not appear to be any way of using move-semantic in initializer list elements in the current revision of the language.

Specifically, we have:

typedef const E& reference;
typedef const E& const_reference;

typedef const E* iterator;
typedef const E* const_iterator;

const E* begin() const noexcept; // first element
const E* end() const noexcept; // one past the last element

Initializing simple structs using initializer lists with clang

That is a bug in clang++:

http://llvm.org/bugs/show_bug.cgi?id=12670

In your case you can just use the explicit call to the constructor, as you provide in the last code snippet. As of whether the semantics are really the same (will it generate the same code), in most cases it will.

The case where the different syntax will lead to different behavior is when the type being constructed has a constructor that takes a std::initializer_list<>, in which case the brace-initializer will construct that initializer list. If the type does not have such a constructor, as is your case, the brace-initializer will call the appropriate constructor.



Related Topics



Leave a reply



Submit