Why use initializer_list instead of vector in parameters? - c++

What is the actual benefit and purpose of initializer_list, for unknown number of parameters? Why not just use vector and be done with it?
In fact, it sounds like just a vector with another name. Why bother?
The only "benefit" I see of initializer_list is that it has const elements, but that doesn't seem to be a reason enough to invent this whole new type. (You can just use a const vector after all.)
So, what am I mising?

It is a sort of contract between the programmer and the compiler. The programmer says {1,2,3,4}, and the compiler creates an object of type initializer_list<int> out of it, containing the same sequence of elements in it. This contract is a requirement imposed by the language specification on the compiler implementation.
That means, it is not the programmer who creates manually such an object but it is the compiler which creates the object, and pass that object to function which takes initializer_list<int> as argument.
The std::vector implementation takes advantage of this contract, and therefore it defines a constructor which takes initializer_list<T> as argument, so that it could initialize itself with the elements in the initializer-list.
Now suppose for a while that the std::vector doesn't have any constructor that takes std::initializer_list<T> as argument, then you would get this:
void f(std::initializer_list<int> const &items);
void g(std::vector<int> const &items);
f({1,2,3,4}); //okay
g({1,2,3,4}); //error (as per the assumption)
As per the assumption, since std::vector doesn't have constructor that takes std::initializer_list<T> as argument, which implies you cannot pass {1,2,3,4} as argument to g() as shown above, because the compiler cannot create an instance of std::vector out of the expression {1,2,3,4} directly. It is because no such contract is ever made between programmer and the compiler, and imposed by the language. It is through std::initializer_list, the std::vector is able to create itself out of expression {1,2,3,4}.
Now you will understand that std::initializer_list can be used wherever you need an expression of the form of {value1, value2, ...., valueN}. It is why other containers from the Standard library also define constructor that takes std::initializer_list as argument. In this way, no container depends on any other container for construction from expressions of the form of {value1, value2, ...., valueN}.
Hope that helps.

Well, std::vector has to use initializer_list to get that syntax as it obviously can't use itself.
Anyway, initializer_list is intended to be extremely lightweight. It can use an optimal storage location and prevent unnecessary copies. With vector, you're always going to get a heap allocation and have a good chance of getting more copies/moves than you want.
Also, the syntax has obvious differences. One such thing is template type deduction:
struct foo {
template<typename T>
foo(std::initializer_list<T>) {}
};
foo x{1,2,3}; // works
vector wouldn't work here.

The biggest advantage of initializer_list over vector is that it allows you to specify in-place a certain sequence of elements without requiring delicate processing to create that list.
This saves you from setting up several calls to push_back (or a for cycle) for initializing a vector even though you know exactly which elements are going to be pushed into the vector.
In fact, vector itself has a constructor accepting an initializer_list for more convenient initialization. I would say the two containers are complementary.
// v is constructed by passing an initializer_list in input
std::vector<std::string> v = {"hello", "cruel", "world"};
Of course it is important to be aware of the fact that initializer_list does have some limitations (narrowing conversions are not allowed) which may make it inappropriate or impossible to use in some cases.

Related

using memset to initialize vector of structure which contains array

I have following structure
struct a {
int array[20]
int array2[45]
}
I have created vector of this structure
vector<a> vec;
I have used this vec. Now i Want to initialize(setting all array values inside object in the vector element) to zero. How can i do it.?
It turns out that this is a much more interesting question than it first appears.
tl;dr: If you are using a C++03 or later compiler, you don't need to bother.
You need to understand the difference between value initialization and default initialization. Basically value initialization will set all the elements to zero, and default initialization wil leave them all alone. If any of the default elements of the structure (recursively) have a user defined default constructor, then both value and default initialization will call that.
Note that value initialization is much better than memset to zero because
It will call default constructors
It will correctly initialize floating point (to 0.0) and pointers (to NULL). Although memset will probably do that on your implementation, it isn't guaranteed to.
The normal way to create a vector with n elements is just to call:
std::vector<a> vec(n);
C++98
this will call
std::vector<a>::vector(size_type count,
const T& value = T(),
const Allocator& alloc = Allocator());
The value object will be default constructed, and you will need to initialize the elements somehow. The best way to do that, is to provide a properly value initialized value to be copied. So:
const static a azeroed; // Because this is static, it will be value initialized
std::vector<a> vec(20,azeroed);
Technical note: The C++98 standard doesn't contain the term "value initialization", but the initialization of azeroed is identical.
C++03
The same vector constructor is called, but from C++03, the value argument is value initialized (so everything in the garden is rosy).
C++11
The call is to
std::vector<a>::vector(size_type count);
which value initializes the elements directly.
C++14
The call is to
std::vector<a>::vector(size_type count, const Allocator& alloc = Allocator());
(basically, they realized they forgot the allocator argument). There is a very subtle difference here, in that the elements are constructed by calls to Allocator::construct, and although the default allocator will value initialize the elements, it is possible to provide a custom version which doesn't (see this answer). If you are doing that, you almost certainly know what you are doing.
Conclusion
Unless you are using a real C++98 compiler, you don't need to call memset
Providing an explicitly value initialized value to the vector constructor is safer than calling memset.
memset may not properly initialize non-integral built-in values (although it probably will).
memset will definitely clobber anything will a proper constructor. This is a huge maintenance hazard. If a maintenance programmer changes the structure so it is no longer POD, the code will still compile - it will just do the wrong thing.
There is a lot to be said for just giving the struct a proper default constructor, and then you never have to worry about whether any of the elements are initialized, even if you have a local copy.
Reading the comments, there's code you haven't shown that populated your vector. Now you'd like to reuse the storage instead of creating a new one, and you want to re-initialize it.
The canonical answer for any algorithm for any C++ container is likely found among the standard algorithms. In this case, std::fill. Initialize your structure how you like, and copy that to your vector. Along these lines:
a A = {0};
std::fill(vec.begin(), vec.end(), A);
If you're tempted to say that's not fast enough, check. I think you'll find it's quite efficient. The above code is absolutely safe, and works for any correctly initialized argument to fill. I doubt it can be made faster without making some assumptions about the implementation of a.

How I can use emplace for unordered_set that holds shared_ptr to the object?

Say I have an object:
struct Foo {
Foo(const std::string& str1, const std::string& str1)
: mStr1(str1), mStr2(str2)
{}
std::string mStr1;
std::string mStr2;
};
And set
typedef std::unordered_set<std::shared_ptr<Foo> , Hash, Compare> Set;
I have custom hasher and compare. But when I say:
Set set;
set.emplace(str1, str2);
I receive compile error, because the constructor of Foo is obviously not a constructor of std::shared_ptr<Foo>. What I would like is when emplace needs to construct a pointer to use std::make_shared<Foo>(str1, str2)
It seems that I also need a custom allocator for that, but I did not manage to implement one that satisfy the compiler.
My question is: Is what I want possible. If yes, how - is the allocator the right way to go. If yes, can you point me to an example.
Use set.insert(std::make_shared<Foo>(str1, str2));. emplace is generally not a gain for container with unique keys when duplicate keys are an issue, because of the way it operates:
It must construct the object first before it can compare it to existing keys in the container to determine if it can be inserted.
Once the object is constructed, it cannot be copied or moved, because the object is not required to be copyable or movable. Moreover, there's no reliable way for emplace to detect when it can copy or move something, because there are plenty of types for which is_copy_constructible returns true but cannot be actually copied.
Object construction can only happen once, since the constructor may move from the arguments or have other side effects.
A typical implementation of emplace thus always allocates memory for the node up-front, constructs the object inside that memory, compares it with existing elements in the container, and then either links it in, or destroys it and deallocates the memory.
insert, on the other hand, has the key readily available. It can therefore first decide whether the node should be inserted, and only allocate memory if it should be.
In theory, implementations might special-case emplace for the "one argument with the same type as the element type" case. But I know of no implementation that actually does this.
You can just use std::make_shared directly in the argument list of emplace.
set.emplace(std::make_shared<Foo>(str1, str2));
No custom allocator required.
I receive compile error, because the constructor of Foo is obviously
not a constructor of std::shared_ptr. What I would like is when
emplace needs to construct a pointer to use
std::make_shared(str1, str2)
emplace is implemented as a function that uses perfect forwarding to invoke the constructor of the contained element (in this case shared_ptr). The contained element's constructor accepts a pointer to Foo, therefore you should be able to do this (just like you would construct a shared_ptr<Foo> object):
set.emplace(new Foo("x", "y")); //or
set.emplace(new Foo(str1, str2));
It seems that I also need a custom allocator for that, but I did not
manage to implement one that satisfy the compiler.
A custom allocator is a total overkill if all you want to do is add a shared_ptr in the most efficient way (by invoking forwarding constructor on some pre-allocate element), or I'm totally misunderstanding your question. You would typically use the allocator if you don't want the element to be constructed using the default allocator (which use operator new). In this case, shared_ptr itself will be the element that will be constructed on the heap. You would only use an allocator if you are concerned that heap allocations are for some reason inefficient for your purposes (e.g if you allocate millions of small objects).
Note (as commented by #Yakk) that, in this case it is possible that the instantiation of shared_ptr may throw (I can only think of bad_alloc as possibility), in which case the pointer passed to emplace would cause a leak. For this reason I too think std::make_shared would be a better option (as mentioned in another answer).

non-const elements initializer_list class

I want to have initializer_list as a parameter in my function in order to use an undetermined amount of a specific type of variable. It must be a initializer_list because I want to be able to create the list on the function call and because I pass the list into other subfunctions. However, I need to be able to modify the elements in the list and I can't because initializer_list automaticly makes the pointers of type const.
So my question is how do I go about making my own initializer_list class? Making a copy of the header with const removed didn't work and I can't seem to find the answer anywhere.
You can't. std::initializer_list is a magic type that is intricately tied to the compiler, and there is no way to create your own type with the same ability to be constructed from a braced-init-list.
In that sense it's a bit like std::typeinfo and std::nullptr_t. They happen to be defined in namespace std and so appear to be part of the standard library, but they are actually predefined types that are part of the run-time environment and cannot be emulated in pure C++.
I think you might be able to just use a vector.
void foo(std::vector<int> values);
is callable with
foo({ 1, 2, 3, 4 });
and then you can pass (move) the vector around as usual and the elements are modifyable of course.
You can't do this directly. However, I did kind of workaround in my code sometime ago.
First, a slice type which is a non-owning wrapper around contiguous chunk of memory - a pointer to its start and its size.
Second, I added following ctor:
slice(std::initializer_list<T> && list)
: slice((T*)list.begin(), list.size())
{ }
where T is slice's type. This works well on G++ 4.8 and 4.9, though I didn't check it on 5.X versions.
This is definitely a hack, but you'll be able to use slice<T> as function argument, and then (with enough variety of implicit constructors) pass any contiguous container there, including array, vector and initializer_list. With full support for moves.
Hope this helps.

Pass initializer list or container, looking towards move semantics?

EDIT: Before we begin, this question is not about proper usage of std::initializer_list; it is about what should be passed when the convenient syntax is desired. Thank you for staying on topic.
C++11 introduces std::initializer_list to define functions accepting braced-init-list arguments.
struct bar {
bar( char const * );
bar( int );
} dog( 42 );
fn foo( std::initializer_list< bar > args );
foo( { "blah", 3, dog } );
The syntax is nice, but under the hood it is distasteful due to various problems:
They cannot be meaningfully moved. The above function must copy dog from the list; this cannot be converted to move-construction or elided. Move-only types cannot be used at all. (Well, const_cast would actually be a valid workaround. If there's an article about doing so, I'd like to see it.)
There are no constexpr semantics, either. (This is forthcoming in C++1y. It's a minor issue, though.)
const does not propagate as it does everywhere else; the initializer_list is never const but its contents always are. (Because it doesn't own its contents, it cannot give write access to a copy, although copying it anywhere would seldom be safe.)
The initializer_list object does not own its storage (yikes); its relationship to the completely separate naked array (yikes) providing the storage is hazily defined (yikes) as the relationship of a reference to a bound temporary (quadruple yikes).
I have faith these things will be fixed in due time, but for now is there a best practice to get the advantages without hard-coding to initializer_list? Is there any literature about or analysis into working around direct dependency on it?
The obvious solution is to pass by value a standard container such as std::vector. Once the objects are copied into it from the initializer_list, it is move-constructed to pass by value, and then you can move the contents out. An improvement would be to offer storage on the stack. A good library might be able to offer most of the advantages of initializer_list, array, and vector, without even using the former.
Any resources?
it is about what should be passed when the convenient syntax is desired.
If you want the convenience of size (ie: the user just types a {} list with no function calls or words), then you must accept all the powers and limitations of a proper initializer_list. Even if you try to convert it into something else, like some form of array_ref, you still have to have an intermediary initializer_list between them. Which means that you can't get around any of the issues you've run into, like not being able to move out of them.
If it goes through an initializer_list, then you have to accept these limitations. Therefore, the alternative is to not go through an initializer_list, which means that you're going to have to accept some form of container with specific semantics. And the alternative type would have to be an aggregate, so that the construction of the alternate object won't encounter the same problem.
So you're probably looking at forcing the user to create a std::array (or a language array) and passing that. Your function could take some form of array_ref class, which can be constructed from any array of arbitrary size, so the consuming function isn't limited to one size.
However, you lose the convenience of size:
foo( { "blah", 3, dog } );
vs.
foo( std::array<bar, 3>{ "blah", 3, dog } );
The only way to avoid the verbosity here is to have foo take std::array as a parameter. Which means that it could only take an array of a specific fixed size. And you couldn't use C++14's proposed dynarray, because that will use an initializer_list intermediary.
Ultimately, you shouldn't be using uniform initialization syntax for passing around lists of values. It's for initializing objects, not for passing lists of things. std::initializer_list is a class who's sole purpose is to be used to initialize a specific object from an arbitrarily long list of values of identical types. It is there to serve as an intermediary object between a language construct (a braced-init-list) and the constructor that these values are to be fed into. It allows the compiler to know to call a particular constructor (the initializer_list constructor) when given a matching braced-init-list of values.
This is the entire reason why the class exists.
Therefore, you should use the class exclusively for the purpose for which it was devised. The class exists to tag a constructor as taking a list of values from a braced-init-list. So you should use it only for constructors that take such a value.
If you have some function foo that acts as an intermediary between some internal type (that you don't want to directly expose) and a user-provided list of values, then you need to take something else as a parameter to foo. Something that has the semantics you desire, which you can then feed into your internal type.
Also, you seem to have a misconception around initializer_lists and movement. You cannot move out of an initializer_list, but you can certainly move into one:
foo( { "blah", 3, std::move(dog) } );
The third entry in the internal dog array will be move-constructed.

custom allocator using move for vector of thread

I'm currently learning about concurrency in C++ and came across using a vector of threads, which I believe will be possible in C++0x. However, my current compiler doesn't appear to have an implementation of move-aware containers and so I get errors generated because std::thread::thread(const std::thread&) is deleted, ie I can only use the move constructor/move assignment with std::thread.
Am I correct in thinking I could circumvent this issue by writing a custom allocator using
void MyAllocator::construct (pointer p, reference val)
/* should be non-const reference to val because using move constructor? */
{
new ((void*)p) T (std::move(val));
}
rather than
void allocator::construct (pointer p, const_reference val)
{
new ((void*)p) T (val);
}
? Or some other variation on this theme (possibly using an overload of MyAllocator::construct).
NB: This is mainly intended to be a short-term educational exercise and well enough performing work around to play around with threads in containers. I'd only be using MyAllocator in this context. However, please also point me at any libraries that may have this implemented so I can have a poke around the source.
If your compiler doesn't provide a move-aware std::vector then you'll have to write your own specialization of std::vector<std::thread> rather than just provide a custom allocator. The whole C++03 vector interface relies on copying: push_back() copies elements in; resize() initializes the empty elements with a copy of the element passed as the second parameter (even if that is the default value of T()); resize(), reserve(), insert(), erase() and push_back() will copy elements if the vector needs reallocating, or elements otherwise need moving around, and so forth.
This is such a common problem that I've included such a specialization with my (commercial) just::thread implementation of std::thread.
The easiest way to circumvent the problem would be to allocate the threads on the heap and manipulate pointers to them.
Check the Boost Pointer Container library: boost::ptr_vector<std::thread> seems to me what you are looking for.
The requirement that std containers only take copyable objects has more to do with the C++03 container interfaces than it does with the allocator implementation.
For example
vector<T> b(100);
vector<T> a;
a=b;
assert(a==b);
The standard assures us a==b is true. However, if T were not copyable, then in the best case a=b will not compile, in the worst a=b is undefined. Furthermore,
a.push_back(T());
may cause a to allocate new space, and under the hood there are copies made to the new underlying storage from the old.
Furthermore, there is nothing in the C++03 standard that says an implementation actually has to call allocator.construct, and in fact many (gcc for example) do not.
The C++0x standard adds new member functions to the container interface for moveable types, and clarifies how things like operator= behave in their presence.
See www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2486.pdf