In class Foo, I have a member variable of type Bar. Bar is constructed in my Foo constructor by passing in a pointer to an array like this:
template<typename> T
class Foo{
Bar myBar;
size_t mySize;
size_t top;
Foo(size):myBar(new T[size]),mySize(size),top(0){}; //creates a Bar element of certain size
}
template<typename> T
class Bar{
T* myListPtr;
Bar::Bar(T* tPtr):myListPtr(tPtr){} //stores a pointer to a T array
}
Now to my knowledge, if T has a default constructor, C++ should be calling this on all elements in the array. However when I output the values that are being pointed to, I got an array like this(with size=8 and T type 'double')
9.3218e-306
0
0
0
0
3.81522e-270
nan
nan
How do I make sure that all the values are default initialized and not just some. This array might hold char, double, any type, but the type will always have have a default constructor. What could be causing this problem?
Now to my knowledge, if T has a default constructor, C++ should be calling this on all elements in the array. However when I output the values that are being pointed to, I got an array like this(with size=8 and T type 'double')
You are correct in that the default constructor will be used if one exists. However primitive types like double (and int, float, char, etc) do not have constructors, default or otherwise. Although the language lets you work with primitive types and class types with the same syntax in many cases, this is a fundamental difference.
So given a class MyClass then
MyClass myInstance;
will call its default constructor.
But given a double, then
double myDouble;
will not initialize it in any way.
As a consequence, creating an array of doubles as you do in your example will not initialize them.
Now the next logical question would be how to initialize them. This stackoverflow question provides an answer and also gives the worthwhile advice that using std::vector can help avoid some of the troubles that raw arrays often have.
Related
I understand that memberwise assignment of arrays is not supported, such that the following will not work:
int num1[3] = {1,2,3};
int num2[3];
num2 = num1; // "error: invalid array assignment"
I just accepted this as fact, figuring that the aim of the language is to provide an open-ended framework, and let the user decide how to implement something such as the copying of an array.
However, the following does work:
struct myStruct { int num[3]; };
struct myStruct struct1 = {{1,2,3}};
struct myStruct struct2;
struct2 = struct1;
The array num[3] is member-wise assigned from its instance in struct1, into its instance in struct2.
Why is member-wise assignment of arrays supported for structs, but not in general?
edit: Roger Pate's comment in the thread std::string in struct - Copy/assignment issues? seems to point in the general direction of the answer, but I don't know enough to confirm it myself.
edit 2: Many excellent responses. I choose Luther Blissett's because I was mostly wondering about the philosophical or historical rationale behind the behavior, but James McNellis's reference to the related spec documentation was useful as well.
Here's my take on it:
The Development of the C Language offers some insight in the evolution of the array type in C:
http://cm.bell-labs.com/cm/cs/who/dmr/chist.html
I'll try to outline the array thing:
C's forerunners B and BCPL had no distinct array type, a declaration like:
auto V[10] (B)
or
let V = vec 10 (BCPL)
would declare V to be a (untyped) pointer which is initialized to point to an unused region of 10 "words" of memory. B already used * for pointer dereferencing and had the [] short hand notation, *(V+i) meant V[i], just as in C/C++ today. However, V is not an array, it is still a pointer which has to point to some memory. This caused trouble when Dennis Ritchie tried to extend B with struct types. He wanted arrays to be part of the structs, like in C today:
struct {
int inumber;
char name[14];
};
But with the B,BCPL concept of arrays as pointers, this would have required the name field to contain a pointer which had to be initialized at runtime to a memory region of 14 bytes within the struct. The initialization/layout problem was eventually solved by giving arrays a special treatment: The compiler would track the location of arrays in structures, on the stack etc. without actually requiring the pointer to the data to materialize, except in expressions which involve the arrays. This treatment allowed almost all B code to still run and is the source of the "arrays convert to pointer if you look at them" rule. It is a compatiblity hack, which turned out to be very handy, because it allowed arrays of open size etc.
And here's my guess why array can't be assigned: Since arrays were pointers in B, you could simply write:
auto V[10];
V=V+5;
to rebase an "array". This was now meaningless, because the base of an array variable was not a lvalue anymore. So this assigment was disallowed, which helped to catch the few programs that did this rebasing on declared arrays. And then this notion stuck: As arrays were never designed to be first class citized of the C type system, they were mostly treated as special beasts which become pointer if you use them. And from a certain point of view (which ignores that C-arrays are a botched hack), disallowing array assignment still makes some sense: An open array or an array function parameter is treated as a pointer without size information. The compiler doesn't have the information to generate an array assignment for them and the pointer assignment was required for compatibility reasons. Introducing array assignment for the declared arrays would have introduced bugs though spurious assigments (is a=b a pointer assignment or an elementwise copy?) and other trouble (how do you pass an array by value?) without actually solving a problem - just make everything explicit with memcpy!
/* Example how array assignment void make things even weirder in C/C++,
if we don't want to break existing code.
It's actually better to leave things as they are...
*/
typedef int vec[3];
void f(vec a, vec b)
{
vec x,y;
a=b; // pointer assignment
x=y; // NEW! element-wise assignment
a=x; // pointer assignment
x=a; // NEW! element-wise assignment
}
This didn't change when a revision of C in 1978 added struct assignment ( http://cm.bell-labs.com/cm/cs/who/dmr/cchanges.pdf ). Even though records were distinct types in C, it was not possible to assign them in early K&R C. You had to copy them member-wise with memcpy and you could pass only pointers to them as function parameters. Assigment (and parameter passing) was now simply defined as the memcpy of the struct's raw memory and since this couldn't break exsisting code it was readily adpoted. As a unintended side effect, this implicitly introduced some kind of array assignment, but this happended somewhere inside a structure, so this couldn't really introduce problems with the way arrays were used.
Concerning the assignment operators, the C++ standard says the following (C++03 §5.17/1):
There are several assignment operators... all require a modifiable lvalue as their left operand
An array is not a modifiable lvalue.
However, assignment to a class type object is defined specially (§5.17/4):
Assignment to objects of a class is defined by the copy assignment operator.
So, we look to see what the implicitly-declared copy assignment operator for a class does (§12.8/13):
The implicitly-defined copy assignment operator for class X performs memberwise assignment of its subobjects. ... Each subobject is assigned in the manner appropriate to its type:
...
-- if the subobject is an array, each element is assigned, in the manner appropriate to the element type
...
So, for a class type object, arrays are copied correctly. Note that if you provide a user-declared copy assignment operator, you cannot take advantage of this, and you'll have to copy the array element-by-element.
The reasoning is similar in C (C99 §6.5.16/2):
An assignment operator shall have a modifiable lvalue as its left operand.
And §6.3.2.1/1:
A modifiable lvalue is an lvalue that does not have array type... [other constraints follow]
In C, assignment is much simpler than in C++ (§6.5.16.1/2):
In simple assignment (=), the value of the right operand is converted to the type of the
assignment expression and replaces the value stored in the object designated by the left
operand.
For assignment of struct-type objects, the left and right operands must have the same type, so the value of the right operand is simply copied into the left operand.
In this link: http://www2.research.att.com/~bs/bs_faq2.html there's a section on array assignment:
The two fundamental problems with arrays are that
an array doesn't know its own size
the name of an array converts to a pointer to its first element at the slightest provocation
And I think this is the fundamental difference between arrays and structs. An array variable is a low level data element with limited self knowledge. Fundamentally, its a chunk of memory and a way to index into it.
So, the compiler can't tell the difference between int a[10] and int b[20].
Structs, however, do not have the same ambiguity.
I know, everyone who answered are experts in C/C++. But I thought, this is the primary reason.
num2 = num1;
Here you are trying to change the base address of the array, which is not permissible.
and of course,
struct2 = struct1;
Here, object struct1 is assigned to another object.
Another reason no further efforts were made to beef up arrays in C is probably that array assignment would not be that useful. Even though it can be easily achieved in C by wrapping it in a struct (and the struct's address can be simply cast to the array's address or even the array's first element's address for further processing) this feature is rarely used. One reason is that arrays of different sizes are incompatible which limits the benefits of assignment or, related, passing to functions by value.
Most functions with array parameters in languages where arrays are first-class types are written for arrays of arbitrary size. The function then usually iterates over the given number of elements, an information that the array provides. (In C the idiom is, of course, to pass a pointer and a separate element count.) A function which accepts an array of just one specific size is not needed as often, so not much is missed. (This changes when you can leave it to the compiler to generate a separate function for any occurring array size, as with C++ templates; this is the reason why std::array is useful.)
I have recently fixed a bug in an application of mine: the problem was that an object that resides on the stack had a field left uninitialized.
The object had a class declaration of this type:
struct A{
int somefield, someotherfield;
A(): someotherfield(0) {}
}
and when declaring a local variable (like A var; in a function), somefield was left uninitialized, and so a read of it would return a randomish value.
I was certain that fields of a class, which don't appear in the constructor initialization list, would always get initialized by a synthesized trivial constructor (in the case of an int, a zero value). Evidently I am wrong.
So what are the general rules about implicit field initialization?
classes and structs are initialized by contructor
Basic types int double char short ... are not initialized and contain random numbers
Pointers are not initialized and point to random positions
arrays of classes or structs cause each element to be initialized by its constructor
arrays of basic types or pointers are random.
I understand from the answer to this question that values of global/static uninitialized int will be 0. The answer to this one says that for vectors, the default constructor for the object type will be called.
I am unable to figure out - what happens when I have vector<int> v(10) in a local function. What is the default constructor for int? What if I have vector<int> v(10) declared globally?
What I am seeing is that vector<int> v(10) in a local function is resulting in variables being 0 - but I am not sure if that is just because of my compiler or is the fixed expected behaviour.
The zero initialization is specified in the standard as default zero initialization/value initialization for builtin types, primarily to support just this type of case in template use.
Note that this behavior is different from a local variable such as int x; which leaves the value uninitialized (as in the C language that behavior is inherited from).
It is not undefined behaviour, a vector automatically initialises all its elements. You can select a different default if you want.
The constructor is:
vector( size_type, T t = T() )
and for int, the default type (returned by int()) is 0.
In a local function this:
int x;
is not guaranteed to initialise the variable to 0.
int x = int();
would do so.
int x();
sadly does neither but declares a function.
The constructor you are using actually takes two arguments, the second of which is optional. Its declaration looks like this:
explicit vector(size_type n, const T& value = T())
The first argument is the number of elements to create in the vector initially; the second argument is the value to copy into each of those elements.
For any object type T, T() is called "value initialization." For numeric types, it gives you 0. For a class type with a default constructor, it gives you an object that has been default constructed using that constructor.
For more details on the "magic parentheses," I'd recommend reading Michael Burr's excellent answer to the question "Do the parentheses after the type name make a difference with new?" It discusses value initialization when used with new specifically, but for the most part is applicable to value initialization wherever else it can be used.
By default, vector elements are zero-initialized and not default-initialized. Those are two different but related concepts:
zero-initialization is what is done for static objects not having an explicit initialization and what is done for a member given in the initialized list with an initializer of (). For basic types, the value used is 0 converted to the type.
default-initialization is what is done for not explicitly initialized non static variables and members. For basic types it stay uninitialized.
(And C++0X introduces value-initialization which is still different).
As mentioned by others, what happens is the zero initialization kicks in. I actually use that a lot in my code (outside of vectors and other classes):
some_type my_var = some_type();
This allows me to make sure that my variables are always properly initialized since by default C/C++ do not initialize basic types (char, short, int, long, float, double, etc.)
Since C++11, you also can do so in your class definitions:
class MyClass
{
...
int my_field_ = 123; // explicit initialization
int your_field_ = int(); // zero initialization
};
For vectors, the std library uses T(). Whatever T() is, it will use that default initialization. For a class, it calls the default constructor. For a basic type, it uses zero ('\0', 0, 0.0f, 0.0, nullptr`).
As mentioned by James McNellis and Nawaz, it is possible to set the value used to initialize the vector as in:
std::vector<int> foo(100, 1234);
That feature is also available when you resize your vector (if the vector shrinks, the default value is ignored):
foo.resize(200, 1234);
So that way you can have a default initialization value. However, it's a be tricky since you have to make sure that all your definitions and resize() calls use that default value. That's when you want to write your own class which ensures that the default value is always passed to the vector functions.
However, if you want to have a way to auto-initialize to a specific value, you can mix both features this way:
struct my_value {
int v = 123;
};
std::vector<my_value> foo(100);
// here foo[n].v == 123 for n in [0, 100)
This is my preferred way of dealing with this issue (i.e. if I don't want zero by default). It's an extra .v, but much less prone to mistakes and you don't need to know of the default value when you create a vector of my_value.
Also, for those who think this will be slow, it won't. The struct is like syntactic sugar as far as C++ is concerned. One optimized, it will be exactly the same as a simple std::vector<int> foo(100, 123).
The default initialization for an int type is to initialize it to 0.
This is true of most (if not all) primitive types: char will initialize to (char)0 (or '\0' if you prefer), float will initialize to 0.0f, and any pointer initializes to NULL. For other types, the parameterless constructor is invoked.
In general, the default initialization should happen pretty much whenever you aren't able to specify a constructor (or choose not to).
What will be solution in the following code
Class A{}
void func(){}
printf("%d,%d",sizeof(A),sizeof(func));
Size of an empty class is non zero(most probably 1), so as to have two objects of the class at different addresses.
http://www2.research.att.com/~bs/bs_faq2.html#sizeof-empty explains it better
class A{};
void func(){}
std::cout<<sizeof(A)<<std::endl<<sizeof(&func));// prints 1 and 4 on my 32 bit system
You are taking the size of a function which cannot be done. You need to preceede the name with a & to take the size of a pointer to that function. You also need to cast the sizeof value to be of type int, which is what printf expects for the d specifier
printf("%d,%d", (int)sizeof(A), (int)sizeof(&func));
As for the concrete values ---- It's not known what they are beyond that are greater or equal to 1. It depends on the compiler.
By sizeof(func), you probably mean sizeof(&func), which is the size of a function pointer in bytes.
As far as what the size of an A object is, the standard only says:
Complete objects and member subobjects of class type shall have nonzero size.
which is qualified by footnote 94:
Base class subobjects are not so constrained.
The reason for the footnote is to allow for a compiler optimization known as empty member optimization, which is commonly used in template libraries to access routines of a class type (e.g. allocator routines of an allocator class type) without needing a member object of that class type.
Is it type[]? For example, could I have
T<int[]>;
for some template T.
The type of an "array of type T" is T [dimension], which is what you could pass as template parameters. E.g.:
someTemplate<int [10]> t; // array type as template parameter
int a[5]; // array of 5 ints named 'a'
Arrays need to have a dimension which must be greater than 0. This means that e.g. U u[]; is illegal.
There are cases that might seem like exceptions, the first being parameters:
void f(T[]);
This is a special rule for parameters and f() is actually equivalent to the following:
void f(T*);
Then there is direct inialization of arrays:
int a[] = { 1, 2, 3, 4 };
Here the array size is implicitly given through the number of elements in the initializer, thus the type of a is int[4].
There are also incomplete array types without specificied bounds, but you can't directly create instances of these (see Johannes answer for more):
template<class T> struct X { typedef T type; };
X<int[]>::type a = { 1, 2, 3 };
If you are looking for dynamic arrays, prefer standard containers like std::vector<T> instead.
There are two syntaxes to denote array types. The first is the type-id syntax and is used everywhere where the language expects a compile time type, which looks like:
T[constant-expression]
T[]
This specifies an array type that, in the first form, has a number of elements given by an integer constant expression (means it has to be known at compile time). In the second form, it specifies an array type with an unknown number of elements. Similar to class types that you declare without a body, such an array type is said to be incomplete, and you cannot create arrays of that type
// not valid: what size would it have?
int a[];
You can, however, specify that type. For example you may typedef it
typedef int unknown_int_array[];
In the same manner, you may specify it as a template type argument, so the answer to your question is yes you can pass such a type specifier to a template. Notice that i talk about specifiers here, because the form you use here is not the type itself.
The second way is using the new-type-id syntax which allows denoting runtime types by having non-constant bounds
T[expression]
This allows passing variables as element count, and also allows passing a zero. In such a case, a zero element array is created. That syntax is only usable with the new operator for supporting dynamic arrays.
If possible, you might consider instead using dynamic arrays, and passing in a pointer as the templated type. Such as...
T<int*> myVar;
This started as a comment to Georg's answer, but it ran a bit long...
It seems that you may be missing some key abstraction in your mental model of arrays (at least C-style ones). Local arrays are allocated on the stack with a hard-coded size. If you have an array inside a class or struct, the space for the array is part of the object itself (whether on the stack or heap). Global arrays may even be represented directly in the size of the executable.
This means that any time you want to use an array, you must specify its size to the compiler. The only reason you can leave the brackets empty in a parameter list is because functions treat array parameters as pointers. The function would hardly be useful if it could only operate on one size of array.
Templates are no exception. If you want the size of the templated array to vary, you can add an extra template parameter. You still have to specify the size at compile time for any given instance, though.
The syntax for declaring arrays is
<type> <variable>[<size>];
When using a template the declaration is, in example
template <class T>
T var[4];