Can I specify default value? - c++

Why is it that for user defined types when creating an array of objects every element of this array is initialized with the default constructor, but when I create an array of a built-in type that isn't the case?
And second question: Is it possible to specify default value to be used while initializing elements in the array? Something like this (not valid):
char* p = new char[size]('\0');
And another question in this topic while I'm with arrays. I suppose that when creating an array of user defined type, every element of this array will be initialized with default value. Why is this?
If arrays for built in types do not initialize their elements with their defaults, why do they do it for User Defined Types?
Is there a way to avoid/circumvent this default construction somehow? It seems like bit of a waste if I for example have created an array with size 10000, which forces 10000 default constructor calls, initializing data which I will (later on) overwrite anyway.
I think that behaviour should be consistent, so either every type of array should be initialized or none. And I think that the behaviour for built-in arrays is more appropriate.

That's how built-in types work in C++. In order to initialize them you have to supply an explicit initializer. If you don't, then the object will remain uninitialized. This behavior is in no way specific to arrays. Standalone objects behave in exactly the same way.
One problem here is that when you are creating an array using new[], you options for supplying an initializer (in the current version of the language) are very limited. In fact, the only initializer you can supply is the empty ()
char* p = new char[size]();
// The array is filled with zeroes
In case of char type (or any other scalar type), the () initializer will result in zero-initialization, which is incidentally what you tried to do.
Of course, if your desired default value in not zero, you are out of luck, meaning that you have to explicitly assign the default values to the elements of the new[]-ed array afterwards.
As for disabling the default constructor call for arrays of types with user-defined default constructor... well, there's no way to achieve that with ordinary new[]. However, you can do it by implementing your own array construction process (which is what std::vector does, for one example). You first allocate raw memory for the entire array, and then manually construct the elements one-by-one in any way you see fit. Standard library provides a number of primitive intended to be used specifically for that purpose. That includes std::allocator and functions like uninitialized_copy, uninitialized_fill and so on.

Something like this (not valid):
As far as I know that is perfectly valid.
Well not completely, but you can get a zero intialized character array:
#include <iostream>
#include <cstdlib>
int main(int argc, char* argv[])
{
//The extra parenthesis on the end call the "default constructor"
//of char, which initailizes it with zero.
char * myCharacters = new char[100]();
for(size_t idx = 0; idx != 100; idx++) {
if (!myCharacters[idx])
continue;
std::cout << "Error at " << idx << std::endl;
std::system("pause");
}
delete [] myCharacters;
return 0;
}
This program produces no output.
And another question in this topic while I'm with arrays. I suppose that when creating an array of user defined type and knowing the fact that every elem. of this array will be initialized with default value firstly why?
Because there's no good syntactic way to specialize each element allocated with new. You can avoid this problem by using a vector instead, and calling reserve() in advance. The vector will allocate the memory but the constructors will not be called until you push_back into the vector. You should be using vectors instead of user managed arrays anyway because new'd memory handling is almost always not exception safe.
I think that behaviour should be consistent, so either every type of array should be initialized or none. And I think that the behaviour for built-in arrays is more appropriate.
Well if you can think of a good syntax for this you can write up a proposal for the standard -- not sure how far you'll get with that.
Why is it that for user defined types when creating an array of objects every element of this array is initialized with the default constructor, but when I create an array of a built-in type that isn't the case? and
And another question in this topic while I'm with arrays. I suppose that when creating an array of user defined type, every element of this array will be initialized with default value. Why is this? and
If arrays for built in types do not initialize their elements with their defaults, why do they do it for User Defined Types?
Because a user defined type is never ever valid until its constructor is called. Built in types are always valid even if a constructor has not been called.
And second question: Is it possible to specify default value to be used while initializing elements in the array? Something like this (not valid):
Answered this above.
Is there a way to avoid/circumvent this default construction somehow? It seems like bit of a waste if I for example have created an array with size 10000, which forces 10000 default constructor calls, initializing data which I will (later on) overwrite anyway.
Yes, you can use a vector as I described above.

Currently (unless you're using the new C++0x), C++ will call the constructor that takes no arguments e.g. myClass::myClass(). If you want to initialise it to something, implement a constructor like this that initialises your variables. e.g.
class myChar {
public:
myChar();
char myCharVal;
};
myChar::myChar(): myCharVal('\0') {
}

The C++ philosophy is - don't pay for something you don't need.
And I think the behviour is pretty unified. If your UDT didn't have a default constructor, nothing would be run anyway and the behaviour would be the same as for built-in types (which don't have a default constructor).

Why is it that for user defined types when creating an array of objects every element of this array is initialized with the default constructor, but when I create an array of a built-in type that isn't the case?
But if the default constructor of an object does nothing then it is still not initialiized.
class X
{
public:
char y;
}
X* data = new X[size]; // defaut constructor called. But y is still undefined.
And second question: Is it possible to specify default value to be used while initializing elements in the array? > Something like this (not valid):
Yes:
char data1[size] = { 0 };
std::vector<char> data2(size,0);
char* data3 = new char[size];
memset(data3,0,size);
Is there a way to avoid/circumvent this default construction somehow? It seems like bit of a waste if I for example have created an array with size 10000, which forces 10000 default constructor calls, initializing data which I will (later on) overwrite anyway.
Yes. Use a std::vector.
You can reserve the space for all the elements you need without calling the constructor.
std::vector<char> data4;
data4.reserve(size);

Related

Function Pointer Array Initialization

Consider an array of function pointers within a class in c++14:
class myClass {
myClass();
void (* myFunctions [5])();
}
This array will be populated in other parts of the code, and it is not guaranteed that the array will actually hold as many function pointers as it can (5 in the example). So before calling any of the functions referred to by the array i'd need to check whether the pointer I'm trying to use actually stores something. My idea was to compare the pointer against nullptr, and assume that it points to a valid function if the test fails, i.e. in some function of that class:
if(myFunctions[x] == nullptr) {
// Handle error
return;
}
// Use myFunctions[x]
I was wondering if I need to initialize the array before making that kind of speculation. How is this array initialized if I only write the above two lines of code? Can I assume something like myFunctions[x] == nullptr is true in that case? Or do I need to do an explicit initialization like the following one?
for(int i = 0; i < dimension; i++)
myFunctions[i] = nullptr;
I've found the zero initialization page on cppreference.com, but as I'm learning c++ and I'm still very unexperienced I wasn't able to understand whether this applies in my case. I've also tried to test the pointers by printing their value without assigning any function address and got 0 0 0 0 0, but I don't think the result is reliable: this program is for a microcontroller, and it's possible that the "garbage" values on the stack are all 0s since it is emptied during each code upload.
I don't think that you have to initialize the array, although I'd encourage you to do that. The reason why the array is default-initialized in your case is because you provide a constructor and do not mention the data member in the initializer list (cf. cppreference/default initialization):
Default initialization is performed in three situations:
...
3) when a base class or a non-static data member is not mentioned in a
constructor initializer list and that constructor is called.
Hence, default initialization will take place.
Anyway, in order to express that you rely on a data member to be "zero" without enforcing in other ways that non-initialized entries will not be accessed, I'd make the initialization explicit, e.g.
class myClass {
myClass();
void (* myFunctions [5])() = { };
}

Incompatible types in assignment with struct's data (same type!)

I have a struct:
struct record {
char team[40];
}
And I try to copy its attribute to another stuct.
struct record rec2;
struct record rec;
rec.team = rec2.team;
Except, I get the following compile-time error on the rec.team = rec2.team line:
error: incompatible types in assignment
The same problem occurs if I hard-code the values.
My understanding is that this is not possible, but it is clearly happening anyway. I would appreciate any insight into what is happening here.
Arrays aren't assignable.
Assuming you're really using C++, one obvious alternative would be to use a std::vector or std::string, either of which is assignable.
If you can't do that, you can create some class as a wrapper around your array, then include an instance of that class in your record. As Jonathan Leffler was kind enough to remind us, wrapping the array in a struct makes it assignable, even though the array by itself isn't.
If you can't do that for some reason, you can use std::copy (in C++) or memcpy (in C) to copy the contents of the array. At least in my opinion, this should definitely be your last choice though, as it puts the burden of correctly copying the data from one field to another on the user of the code, instead of letting the code make it easy for the user.
Arrays have no the copy assignment operator. So you should copy one array into another. In your case you could simply assign one structure another structure that is you could simply write
rec = rec2;
As it seems you are using C code then that to copy arrays you should use standard function memcpy declared in header <string.h>
For example
memcpy( rec.team, rec2.team, 40 );
Or if the arrays contain strings then you could use function strcpy or strncpy. For example
strcpy( rec.team, rec2.team );
If you are using C++ then you also could use standard function std::strcpy or std::strncpy because the arrays are public data members of the structure. There is no any need to declare a constructor.
The other way is to use standard class std::array. For example
#include <array>
struct record{
std::array<char, 40> team;
};
record rec, rec2;
//.. some other code
rec = rec2;
Note that when declaring some type a[N] array:
You cannot set a to a different value
The value of a is equal to the address of a
Unlike other types of variables, an array does not have an l-value.
So in essence, you can consider the name of an array as a constant label.
If you want to copy the contents of one array into another, then you can either use any standard memory-copy routine, or implement it yourself.
Example #1:
memcpy(rec.team,rec2.team,40*sizeof(char));
Example #2:
for (int i=0; i<40; i++)
rec.team[i] = rec2.team[i];

C++ How do you set an array of pointers to null in an initialiser list like way?

I am aware you cannot use an initialiser list for an array. However I have heard of ways that you can set an array of pointers to NULL in a way that is similar to an initialiser list.
I am not certain how this is done. I have heard that a pointer is set to NULL by default, though I do not know if this is guaranteed/ in the C++ standard. I am also not sure if initialising through the new operator compared to normal allocation can make a difference too.
Edit: I mean to do this in a header file/constructor initialisation list. I do not want to put it in the constructor, and I do not want to use a Vector.
In order to set an array of pointers to nulls in constructor initializer list, you can use the () initializer
struct S {
int *a[100];
S() : a() {
// `a` contains null pointers
}
};
Unfortunately, in the current version of the language the () initializer is the only initializer that you can use with an array member in the constructor initializer list. But apparently this is what you need in your case.
The () has the same effect on arrays allocated with new[]
int **a = new int*[100]();
// `a[i]` contains null pointers
In other contexts you can use the {} aggregate initializer to achieve the same effect
int *a[100] = {};
// `a` contains null pointers
Note that there's absolutely no need to squeeze a 0 or a NULL between the {}. The empty pair of {} will do just fine.
Normally an array will not be initialised by default, but if you initialise one or more elements explicitly then any remaining elements will be automatically initialised to 0. Since 0 and NULL are equivalent you can therefore initialise an array of pointers to NULL like this:
float * foo[42] = { NULL }; // init array of pointers to NULL
You can switch from array to std::vector and use
std::vector<T*> v(SIZE);
The values will be initialized by NULLs automatically. This is the preferred C++ way.
Update: Since C++11, there is one more way: using
std::array<T*, SIZE> array = {};
This behaves more like a corrected version of C-style array (in particular, avoids dynamic allocations), carries its size around and doesn't decay to a pointer. The size, however, needs to be known at compile time.
I am not certain how this is done. I have heard that a pointer is set to NULL by default, though I do not know if this is guaranteed/ in the C++ standard.
It is not guaranteed by the C++ standard. Built in types ( like pointers ) are filled with garbage unless set otherwise.
I am also not sure if initialising through the new operator compared to normal allocation can make a difference too.
What do you mean by "normal allocation" ? If you're talking about an automatic variable, then you can do this:
MyType * pointers[2] = {}
and the pointers should be initialized to NULL.
void* p[10] = { 0 };
If you have a member array then there is no way to initialize, unless it's a static member. If the array isn't a static member then you'll have to fill it inside the constructor's body.
That said, chances are you're really better off using a std::vector. Other than for technical reasons such as unavailability of a standard STL for your platform, or the slightly lesser performance a std::vector is better than an array by any and all criteria. If performance is the issue then make sure you profiled and know by numbers that it is an issue.

Does a type require a default constructor in order to declare an array of it?

I noticed that when you declare an array, the default constructor must be needed. Is that right?
Is there any exception?
For example,
struct Foo{
Foo(int i ) {}
};
int main () {
Foo f[5];
return 0;
}
The code above does not compile.
Other answers are all right but, for completeness: You could also use the array initialization syntax:
Foo f[5] = {1,2,3,4,5};
This works if Foo's ctor is not explicit. If it was, you'd have to be.... explicit:
Foo f[5] = {Foo(1), Foo(2), Foo(3), Foo(4), Foo(5)};
Note1: There is a difference between the two cases that may not be obvious and is thus worth noting: In the first, the array elements are directly constructed from the ints in the initialization list, by invoking the Foo(int) ctor. In the second, the initialization list is made of Foos constructed with the explicit Foo(int) ctor, and the array elements are copy constructed from the elements in the initialization list. A copy ctor for Foo is thus required in the latter case.
[1] Thanks to MSalters for the comment.
The issue has nothing to do with arrays at all.
When you default-initialize an object of class type, the default constructor is required. If your class has no default constructor, then you have no other choice but to supply an explicit initializer when creating objects of that class. That's all.
By declaring a non-default constructor in your class Foo, you disabled the implicit generation of the default one, so now you'll have to supply an initializer every time you create a Foo object, regardless of whether it is an array element or not.
This declaration
Foo f; // ERROR
is not an array, but it will not compile for the very same reason. In order for it to compile you'll have to supply an explicit initializer
Foo f(3); // OK
The same thing happens with array, except that in that case you have to supply an initializer for each element using the aggregate initializer syntax
Foo f[5] = { 1, 2, 3, 4, 5 };
Of course, if you end up in a context where aggregate initializer syntax is not allowed (in the current version of C++ standard), like constructor initializer list or new-expression, then you are indeed screwed. In such contexts the only way out is to provide the default constructor in array element type (as long as you stick with built-in arrays).
That code doesn't compile because the compiler doesn't know what you want to pass to the constructor of each element, of course. There are basically two ways to go about it:
Make the array a vector, and pass it the desired size plus a single element -- this gives each element the same argument.
Make the array an array of pointers, and construct each element using a for loop and the new operator. The drawback of course, is that you have to free each element later as well.
See the C++ FAQ Lite, section 10.5
When you create an array, the default constructor gets called for each element in the array.
"If your class doesn't have a default constructor, you'll get a compile-time error when you attempt to create an array "
Prefer to use std::vector instead of the built-in arrays, though.
There is no exception. In what could be seen as exception, there is a compiler declared default constructor.
Note that a default constructor is not required if you use std::vector instead of an array - you can specify the constructor to be used:
std::vector <Foo> f; // OK
std::vector <Foo> f( 5, Foo(0) ); // also OK
No it doesn't.
An array, in C/C++ is a block of memory. Creating an array is reserving that block. Creating the objects is "1. Allocating the space 2. Running the constructors on each block" So, if you have an object without a constructor, you can still make an array of it (since that object has a size and since memory understands "size").
In short, it doesn't make any difference whatsoever. You will be running the constructors as you create the objects to fill the array with, or as said previously, when you assign it to something (which in turn, allocates space, runs the constructor).
Yes, you need the default constructor here because Foo f[5]; actually creates 5 Foos. You can work around this by making it a Foo* f[5] and then creating the 5 Foos with new.
For example:
Foo* f[5];
for(int i = 0; i < 5; ++i) {
f[i] = new Foo(i);
}
// later on...
f[0]->whatever();
Warning: slightly off-topic.
If you have a class without default constructor, you absolutely need to have an array, and you don't want to incur into the overhead of dynamic memory allocation, you can use an array of boost::optionals:
boost::optional<Foo> foos[4]; // Stack storage allocated but no objects
// constructed (roughly equivalent to what
// you get with vector<T>::reserve)
if(foos[2]) // Check if the third element has been constructed
{
foos[2]->bar(); // Access members of Foo with arrow
}
foos[1] = Foo(1, "a"); // Constructs the second element
foos[1].reset(); // Destroy second element (storage remains there though)
Unfortunately, you won't be able to pass this to a function expecting a true Foo[].

Why don't std::vector's elements need a default constructor?

And how can I write my own array class to not need a default constructor for its elements? Right now, when I do the new [] to allocate space, I need a default constructor.
std::vector does not.
How do they do this magic?
std::vector doesn't need the default constructor because it never uses it. Every time it needs to construct an element, it does it by using the copy constructor, because every time it has something to copy: either existing vector element or an element you yourself supplied for copying through a method's parameter (explicitly or implicitly, by relying on a default argument)
You can write a class like that in exactly the same way: every time you need to construct a new element in your array, require the user to supply an element for copying. In this case constructing that original element becomes user's responsibility.
Every time it appears as if std::vector "requires" a default constructor from you, it simply means that somewhere you relied on a default argument of some of the vectors methods, i.e. it was you who tried to default-construct an element, not the vector. The vector itself, again, will never try to default-construct elements.
In order to avoid the default constructor requirement during memory allocation, standard library allocates raw uninitialized memory block and then immediately copy-constructs new elements in that raw memory block (which is something new[] cannot do). This functionality is incapsulated in std::allocator class. You can use std::allocator in your code as well, meaning that the "magic" is immediately available to you too.
Note: The above applies to pre-C++11 version of C++ language specification. C++11 changed a lot of things. And these changes do create situations in which std::vector can use default constructors internally.
Also it might be worth noting that even the original C++98 specification allowed implementations to use function overloading instead of default arguments in order to implement the standard library interface. This means that formally it is possible to have a valid C++98 implementation of std::vector that uses default constructors internally.
std::vector only requires the element to have a default constructor if you use it in a way which requires the default constructor. So this code (stolen from a deleted answer) won't compile, because X does not have a default ctor:
#include <vector>
struct X
{
X(int) {}
};
int main(void)
{
std::vector<X> x(1); // vector of length 1, second argument defaults to X() !!
return 0;
}
But if you write main like this instead:
int main(void)
{
std::vector<X> x; // make empty vector
x.push_back(X(1));
return 0;
}
Then it works fine.
You could allocate a block of bytes, then use placement new to make new instance of T (your parametric type) via copy constructor (not default constructor of course) when new items are pushed to the vector's back. This will not allow to to make "a vector of N default-initialized Ts" (which std::vector can make - which is why it does need T to have a default constructor for this purpose), but you could make vectors that start empty and can have Ts pushed onto them.
For me the std::vector was requiring a default constructor for my class (say T) because I was calling resize() method of the vector, despite I was only calling the method to shrink the vector, but never to grow.