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.
Related
From [basic.life/1]:
The lifetime of an object or reference is a runtime property of the object or reference. A variable is said to have vacuous initialization if it is default-initialized and, if it is of class type or a (possibly multi-dimensional) array thereof, that class type has a trivial default constructor. The lifetime of an object of type T begins when:
storage with the proper alignment and size for type T is obtained, and
its initialization (if any) is complete (including vacuous initialization) ([dcl.init]),
except that if the object is a union member or subobject thereof, its lifetime only begins if that union member is the initialized member in the union ([dcl.init.aggr], [class.base.init]), or as described in [class.union] and [class.copy.ctor], and except as described in [allocator.members].
From [dcl.init.general/1]:
If no initializer is specified for an object, the object is default-initialized.
From [basic.indet/1]:
When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced ([expr.ass]).
[Note 1: Objects with static or thread storage duration are zero-initialized, see [basic.start.static]. — end note]
Consider this C++ program:
int main() {
int i;
i = 3;
return 0;
}
Is initialization performed in the first statement int i; or second statement i = 3; of the function main according to the C++ standard?
I think it is the former, which performs vacuous initialization to an indeterminate value and therefore begins the lifetime of the object (the latter does not perform initialization, it performs assignment to the value 3). If that is so, is it really possible to separate storage allocation from object initialization?
If that is so, is it really possible to separate storage allocation from object initialization?
Yes:
void *ptr = malloc(sizeof(int));
ptr points to allocated storage, but no objects live in that storage (C++20 says that some objects may be there, but nevermind that now). Objects won't exist unless we create some there:
new(ptr) int;
You are getting confused between allocating storage for an object and initializing an object, and they are definitely not the same thing.
In your example, the object i is never initialized. As a local value, it has space reserved for its storage, but it is not initialized with any value.
The second line’s statement assigns a value of 3 to it. This again is not initialization.
Objects with global storage are required by the standard to be both allocated and initialized (to zero or whatever the default initializer does). All other objects are only initialized if the written language construct can support it.
C++ allocators work on this same distinction. The new operator, behind the scenes, both allocates and initializes objects, after which you may assign the object a new value. If you need to, though, you can use the underlying language constructs to manage the two things separately.
For most purposes you do not need to care about the difference between object initialization and assignment in your code. If you get to the point where it matters, you either already know how the concepts differ or need to learn really quickly.
Is initialization performed in the first statement int i; or second statement i = 3; of the function main according to the C++ standard?
The first. The second statement is assignment, not initialization. The second statement marks the point "until that value is replaced ([expr.ass])" from your quotes of the standard.
If [initialization is the first statement] is so, is it really possible to separate storage allocation from object initialization?
Yes, but not in a such a simple example as yours. A common example that comes to mind is a std::vector. Reserving capacity allocates storage space, but that storage is not initialized until an object is added to the vector.
std::vector<int> v; // Allocates and initializes the vector object.
v.reserve(1); // Ensures space has been allocated for an int object.
/*
At this point, the first contained element has space allocated, but has
not yet been initialized. If you want to do nutty things between allocation
and object initialization, this is the place to do it. Note that you are
not allowed to access the allocated space since it belongs to the vector.
You'd have to replicate the inner workings of a vector to do that...
*/
v.emplace_back(3); // Initializes the first contained object.
Quoting the standard
Short version:
There is nothing to quote because the standard does not explicitly prohibit all spurious actions. Compilers avoid spurious actions by their own volition.
Long version:
Strictly speaking, the standard does not guarantee that reserve() does not initialize anything. The requirements imposed on reserve() in [vector.capacity] are more focused on what must be done than on prohibiting spurious activity. The closest it comes to this guarantee is the requirement that the time complexity of reserve() be linear in the size of the container (not in the capacity, but in the current size). This would make it impossible to always initialize everything that was reserved. However, a compiler could still choose to initialize a fixed number of reserved elements, say up to 10 million of them. As long as this limit is fixed, it counts as constant-time complexity, so is allowed by [vector.capacity].
Now let's get real. Compilers are designed to produce fast code, without introducing unnecessary, useless busywork. Compilers do not seek out the possibility of doing additional work simply because the standard does not prohibit it. Except for debug builds, no compiler is going to introduce an initialization when it it not required. The people who view the possibility as something worth considering are language lawyers who lose sight of the big picture. You don't pay for what you don't need. The question to ask here is not "Could you quote the standard supporting that no initialization happens?" but "Could you quote the standard supporting that no initialization is required?" Since the additional work of initialization is not required, it will not happen in practice.
Still, reality means little to some language lawyers, and this question does have that tag. To be thorough, I will demonstrate that it is "possible to separate storage allocation from object initialization" even if you happen to use a pathological, yet standards-compliant, compiler that was over-engineered by masochists. I need only one case to demonstrate "possible", so let's abandon int for a more bizarre, yet fully legal, type.
The sole precondition for reserve() is that the contained type can be move-inserted into the container. This precondition is satisfied by the following class.
class C {
// Default construction is not supported.
C() = delete;
public:
// Move construction is allowed, even outside this class.
C(C &&) = default;
};
I have designed this class to be rather hard to initialize. The only allowed construction is move-construction; in order to initialize an object of this type, you need to already have an object of this type. Who creates the first object? No one. No objects of this type can exist. However, one can still create a vector of these objects (an empty vector, but still a vector).
It is legal to define std::vector<C> v;, and to follow that by a call to v.reserve(1);. This allocates space (1 byte is needed on my system) for an object of type C, and yet there is no possible initialization of this object. QED.
Why is there not only 1 type with the best performance, to define a list at compile time?
The benchmark is clear, the constexpr std::initializer_list is faster, uses even less memory and the IO-reads are astonishingly less over constexpr std::array:
https://build-bench.com/b/1EDAcFjJ6NACk4Pg4tG2nbsEx0A
So why didn't they implement the array subscription methods to std::initializer_list make std::array unnecessary.
The question betrays some misunderstandings about what is going on here.
std::array is an array object. It is an object whose storage size is the storage for its array elements. std::initializer_list is a pointer to an array (one created by the compiler). You can heap-allocate std::array for example; you cannot heap-allocate std::initializer_list. Well, you can, but you'd just be heap allocating a pointer, which usually isn't helpful. This:
auto *p = new std::initializer_list<int>{1, 2, 3, 4};
Is broken code, as it heap allocates a pointer to an array temporary created by the compiler. An array temporary that is immediately destroyed at the end of this statement. So you now have a pointer to an array that does not exist, so using *p or p[x] is undefined behavior.
Doing the same with std::array works fine, because array is an array.
Furthermore, the purpose of std::initializer_list is not to "define a list at compile time". As the name suggests, the point of the type is to create a list for the purpose of initializing an object. This is why the ultimate source of its data cannot be provided by any means other than a specific piece of C++ grammar, one used specifically to initialize objects: a braced-init-list.
You can use std::initializer_list as a quick-and-dirty way of just creating an array of values for some purpose. But that's not the point of the type. That's why it doesn't have an operator[]; because functions that can be initialized from a sequence of values don't tend to need that particular operation. They usually only need to walk it from beginning to end.
What are the reasons behind the change in std::vector::resize from the pre-C++11:
void resize( size_type count, T value = T() );
to the compatible C++11 form:
void resize( size_type count );
void resize( size_type count, const value_type& value);
Paragraph C.2.12 of the Annex C (Compatibility) to the C++11 Standard specifies:
Change: Signature changes: resize
Rationale: Performance, compatibility with move semantics.
Effect on original feature: For vector, deque, and list the fill value passed to resize is now passed by
reference instead of by value, and an additional overload of resize has been added. Valid C++ 2003 code
that uses this function may fail to compile with this International Standard.
The old resize() function was copy-constructing new elements from value. This makes it impossible to use resize() when the elements of the vector are default-constructible but non-copyable (you may want to move-assign them later on). This explains the "Compatibility with move semantics" rationale.
Moreover, it may be slow if you do not want any copy to occur, just new elements to be default-constructed. Also, the value parameter is passed by value in the C++03 version, which incurs in the overhead of an unnecessary copy (as mentioned by TemplateRex in his answer). This explains the "Performance" rationale.
One reason is that default arguments are always passed, i.e. copied in this case. Doing
my_vector.resize(1000000)
would copy 1 million T objects.
In C++11 you now have a choice between copying a user-provided value or default-inserting (i.e. constructing) elements in-place, using the std::allocator_traits<Alloc>::construct() function. This allows resizing of vector with elements that are CopyInsertable but not Copyable.
Note that this change has been done to all sequence containers having a resize() member (vector, deque, forward_list and list), but not for std::string which didn't have a default value argument to begin with.
Update: apart from the Annex to the current Standard cited by #AndyProwl, the original defect report by #HowardHinnant also clarifies:
The problem with passing T by value is that it can be significantly
more expensive than passing by reference. The converse is also true,
however when it is true it is usually far less dramatic (e.g. for
scalar types).
Even with move semantics available, passing this parameter by value
can be expensive. Consider for example vector>:
std::vector<int> x(1000); std::vector<std::vector<int>> v; ...
v.resize(v.size()+1, x);
In the pass-by-value case, x is copied once
to the parameter of resize. And then internally, since the code can
not know at compile time by how much resize is growing the vector, x
is usually copied (not moved) a second time from resize's parameter
into its proper place within the vector.
With pass-by-const-reference, the x in the above example need be
copied only once. In this case, x has an expensive copy constructor
and so any copies that can be saved represents a significant savings.
If we can be efficient for push_back, we should be efficient for
resize as well. The resize taking a reference parameter has been coded
and shipped in the CodeWarrior library with no reports of problems
which I am aware of.
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.
If I have a
class A
{
private:
Widget* widgets[5];
};
Is it guaranteed that all pointers are NULL, or do I need to initialize them in the constructor? Is it true for all compilers?
Thanks.
The array is not initialized unless you do it. The standard does not require the array to be initialized.
It is not initialized if it is on the stack or using the default heap allocator (although you can write your own to do so).
If it is a global variable it is zero filled.
This is true for all conformant compilers.
It depends on the platform and how you allocate or declare instances of A. If it's on the stack or heap, you need to explicitly initialize it. If it's with placement new and a custom allocator that initializes memory to zero or you declare an instance at file scope AND the platform has the null pointer constant be bitwise zero, you don't. Otherwise, you should.
EDIT: I suppose I should have stated the obvious which was "don't assume that this happens".
Although in reality the answer is "it depends on the platform". The standard only tells you what happens when you initialize explicitly or at file scope. Otherwise, it is easiest to assume that you are in an environment that will do the exact opposite of what you want it to do.
And if you really need to know (for educational or optimizational purposes), consult the documentation and figure out what you can rely on for that platform.
In general case the array will not be initialized. However, keep in mind that the initial value of the object of class type depends not only on how the class itself is defined (constructor, etc), but might also depend on the initializer used when creating the object.
So, in some particular cases the answer to your question might depend on the initializer you supply when creating the object and on the version of C++ language your compiler implements.
If you supply no initializer, the array will contain garbage.
A* pa = new A;
// Garbage in the array
A a;
// Garbage in the array
If supply the () initializer, in C++98 the array will still contain garbage. In C++03 however the object will be value-initialized and the array will contain null-pointers
A* pa = new A();
// Null-pointers in the array in C++03, still garbage in C++98
A a = A();
// Null-pointers in the array in C++03, still garbage in C++98
Also, objects with static storage duration are always zero-initialized before any other initialization takes place. So, if you define an object of A class with static storage duration, the array will initially contain null-pointers.