In the following code why is that the two statements are illegal
const int i[] = { 1, 2, 3, 4 };
// float f[i[3]]; // Illegal
struct S { int i, j; };
const S s[] = { { 1, 2 }, { 3, 4 } };
//double d[s[1].j]; // Illegal
int main() {}
Why are they illegal? The textual definition is as follows which i didn't understand.
"In an array definition, the compiler must be able to generate code
that moves the stack pointer to accommodate the array. In both of the
illegal definitions above, the compiler complains because it cannot
find a constant expression in the array definition."
Thanks in advance.
Array sized need to be constant expressions. Try this:
constexpr int i[] = { 1, 2, 3, 4 };
float f[i[3]];
The constexpr keyword was introduced in C++11. Previous versions of C++ had no concept of such general constant expressions, and there was no equivalent concept.
Because C++ doesn't support variable-length arrays, and s[1].j is not a compile-time constant.
What that quote refers to is the fact that f and d are in automatic storage. The run-time will clean their memory automatically when they go out of scope. As such, it must know the size beforehand.
because d is static array, that means that it's size has to be know at compilation time.
Therefore you can't use non-const variables as size parameter.
But you can try
const int i = 3;
double d[i];
for example.
Related
struct led {
const int loc;
int state;
unsigned int stateDuration [];
int stateMode;
unsigned long timestamp;
} led1 = {D0, 0, {500}, 0, 0},
led2 = {D7, 0, {100, 900, 400}, 0, 0};
This gives me a compilation error "too many initializers" (the array size is 0). Is it possible to declare an unsized array in the structure and then initialize it with varying values like in my example, or must I explicitly declare the array to the maximum size needed?
It is illegal to have an array of unknown bound as a non-static member of a struct. [class.mem]/13
Non-static data members shall not have incomplete types.
This is because the size of the class must be known when the closing brace is reached.
Maybe you should make stateDuration a std::vector<unsigned int> instead.
You can do it with GCC, using one its C++ language extensions, but only with the very last element of your struct, because the offsets of fields have to be constant.
See: https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
GCC allows static initialization of flexible array members. This is equivalent to defining a new structure containing the original structure followed by an array of sufficient size to contain the data. E.g. in the following, f1 is constructed as if it were declared like f2.
struct f1 {
int x; int y[];
} f1 = { 1, { 2, 3, 4 } };
If you are using something else, you can still implement the idea, but only with heap-allocated objects (so the initializer block thing will not be possible) and you will need an own new operator taking care of the dynamic part. (Perhaps delete too, I am not sure)
I received lecture slides for C++ that merely mention these without explaining what they mean and what are their differences:
int (*arr)[]={...};
int *(arr[])={...};
int (&arr)[]={...};
int &(arr[])={...}; // not allowed?
What do each of these mean? I tried running a program with some of these, but I'm getting errors because I don't know what to put in the initialization list.
int (*arr)[] = { ... };
This is not an array at all. This is a pointer to an array of unknown size. Note that this a scalar type. It is just a data pointer, no different in nature from any other data pointer. Which means that the only way to use { ... } initializer with it is to specify a single value of proper type inside the { ... }. E.g.
int (*arr)[] = { nullptr };
which is the same as
int (*arr)[] = nullptr;
int *(arr[]) = { ... };
This is indeed an array. The same thing can be expressed as
int *arr[] = { ... };
This is an array of int * pointers. It size will depend on how many initializers are supplied in { ... }. E.g.
int *arr[] = { nullptr, &some_int, &some_other_int };
declares arr as an array of 3 pointers of type int *.
int (&arr)[] = { ... };
This is not an array per se. This is a reference to an array of unknown size. Again, the only legal { ... } initializer in this case would be just one lvalue of type int [] inside the { ... }. If the array was declared const, you'd be able to attach it to a temporary array of ints using this syntax, e.g.
const int (&arr)[] = { 1, 2, 3 };
But without const it is not possible. (I have my doubts about the legality of this even with const though. GCC accepts it.)
int &(arr[]) = { ... };
This is an attempt to declare an array of references. Not allowed.
You need to use the Clockwise/Spiral Rule.
int (*arr)[]={...}; // pointer to array of int
int *(arr[])={...}; // array of int pointers
int (&arr)[]={...}; // a reference to an array of int
int &(arr[])={...}; // an array of int references
The last one though is illegal: Why arrays of references are illegal?
I have a global array, which is indexed by the values of an enum, which has an element representing number of values. The array must be initialized by a special value, which unfortunately is not a 0.
enum {
A, B, C, COUNT
};
extern const int arr[COUNT];
In a .cpp file:
const int arr[COUNT] = { -1, -1, -1 };
The enum is occasionally changed: new values added, some get removed. The error in my code, which I just fixed was an insufficient number of initialization values, which caused the rest of the array to be initialized with zeroes. I would like to put a safeguard against this kind of error.
The problem is to either guarantee that the arr is always completely initialized with the special value (the -1 in the example) or to break compilation to get the developers attention, so the array can be updated manually.
The recent C++ standards are not available (old ms compilers and some proprietary junk). Templates can be used, to an extent. STL and Boost are strongly prohibited (don't ask), but I wont mind to copy or to reimplement the needed parts.
If it turns out to be impossible, I will have to consider changing the special value to be 0, but I would like to avoid that: the special value (the -1) might be a bit too special and encoded implicitly in the rest of the code.
I would like to avoid DSL and code generation: the primary build system is jam on ms windows and it is major PITA to get anything generated there.
The best solution I can come up with is to replace arr[COUNT] with arr[], and then write a template to assert that sizeof(arr) / sizeof(int) == COUNT. This won't ensure that it's initalized to -1, but it will ensure that you've explicitly initialized the array with the correct number of elements.
C++11's static_assert would be even better, or Boost's macro version, but if you don't have either available, you'll have to come up with something on your own.
This is easy.
enum {
A, B, C, COUNT
};
extern const int (&arr)[COUNT];
const int (&arr)[COUNT] = (int[]){ -1, -1, -1};
int main() {
arr[C];
}
At first glance this appears to produce overhead, but when you examine it closely, it simply produces two names for the same variable as far as the compiler cares. So no overhead.
Here it is working: http://ideone.com/Zg32zH, and here's what happens in the error case: http://ideone.com/yq5zt3
prog.cpp:6:27: error: invalid initialization of reference of type ‘const int (&)[3]’ from expression of type ‘const int [2]’
For some compilers you may need to name the temporary
const int arr_init[] = { -1, -1, -1};
const int (&arr)[COUNT] = arr_init;
update
I've been informed the first =(int[]){-1,-1,-1} version is a compiler extension, and so the second =arr_init; version is to be preferred.
Answering my own question: while it seems to be impossible to provide the array with the right amount of initializers directly, it is really easy to just test the list of initializers for the right amount:
#define INITIALIZERS -1, -1, -1,
struct check {
check() {
const char arr[] = {INITIALIZERS};
typedef char t[sizeof(arr) == COUNT ? 1: -1];
}
};
const int arr[COUNT] = { INITIALIZERS };
Thanks #dauphic for the idea to use a variable array to count the values.
The Boost.Preprocessor library might provide something useful, but I doubt whether you will be allowed to use it and it might turn out to be unwieldy to extract from the Boost sources.
This similar question has an answer that looks helpful:
Trick : filling array values using macros (code generation)
The closest I could get to an initialization rather than a check is to use a const reference to an array, then initialize that array within a global object. It's still runtime initialization, but idk how you're using it so this may be good enough.
#include <cstring>
enum {A, B, C, COUNT};
namespace {
class ArrayHolder {
public:
int array[COUNT]; // internal array
ArrayHolder () {
// initialize to all -1s
memset(this->array, -1, sizeof(this->array));
}
};
const ArrayHolder array_holder; // static global container for the array
}
const int (&arr)[COUNT] = array_holder.array; // reference to array initailized
// by ArrayHolder constructor
You can still use the sizeof on it as you would before:
for (size_t i=0; i < sizeof(arr)/sizeof(arr[0]); ++i) {
// do something with arr[i]
}
Edit
If the runtime initialization can never be relied on you should check your implementation details in the asm because the values of arr even when declared with an initializer may still not be known at until runtime initialization
const int arr[1] = {5};
int main() {
int local_array[arr[0]]; // use arr value as length
return 0;
}
compiling with g++ -pedantic gives the warning:
warning: ISO C++ forbids variable length array ‘local_array’ [-Wvla]
another example where compilation actually fails:
const int arr1[1] = {5};
int arr2[arr1[0]];
error: array bound is not an integer constant before ']' token
As for using an array value as a an argument to a global constructor, both constructor calls here are fine:
// [...ArrayHolder definition here...]
class IntegerWrapper{
public:
int value;
IntegerWrapper(int i) : value(i) {}
};
const int (&arr)[COUNT] = array_holder.array;
const int arr1[1] = {5};
IntegerWrapper iw1(arr1[0]); //using = {5}
IntegerWrapper iw2(arr[0]); //using const reference
Additionally the order of initalization of global variables across different source files is not defined, you can't guarantee the arr = {-1, -1, -1}; won't happen until run time. If the compiler is optimizing out the initialization, then you're relying on implementation, not the standard.
The point I really wanna stress here is: int arr[COUNT] = {-1, -1, -1}; is still runtime initialization unless it can get optimized out. The only way you could rely on it being constant would be to use C++11's constexpr but you don't have that available.
I am having the following issue with my code:
int n = 10;
double tenorData[n] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Returns the following error:
error: variable-sized object 'tenorData' may not be initialized
Whereas using double tenorData[10] works.
Anyone know why?
In C++, variable length arrays are not legal. G++ allows this as an "extension" (because C allows it), so in G++ (without being -pedantic about following the C++ standard), you can do:
int n = 10;
double a[n]; // Legal in g++ (with extensions), illegal in proper C++
If you want a "variable length array" (better called a "dynamically sized array" in C++, since proper variable length arrays aren't allowed), you either have to dynamically allocate memory yourself:
int n = 10;
double* a = new double[n]; // Don't forget to delete [] a; when you're done!
Or, better yet, use a standard container:
int n = 10;
std::vector<double> a(n); // Don't forget to #include <vector>
If you still want a proper array, you can use a constant, not a variable, when creating it:
const int n = 10;
double a[n]; // now valid, since n isn't a variable (it's a compile time constant)
Similarly, if you want to get the size from a function in C++11, you can use a constexpr:
constexpr int n()
{
return 10;
}
double a[n()]; // n() is a compile time constant expression
#ifndef QWERT_H
#define QWERT_H
const int x [] = {1, 2,};
const int z = 3;
#endif
#include <iostream>
#include "qwert.h"
class Class
{
int y [x[0]]; //error:array bound is not an integer constant
int g [z]; //no problem
};
int main ()
{
int y [x[0]]; //no problem
Class a_class;
}
I can't figure out why this doesn't work. Other people with this problem seem to be trying to dynamically allocate arrays. Any help is much appreciated.
x is const (as is z obviously), but x[0] is not a constant expression. Array declarations in a class definition must have constant size specifiers.
Consider this for a moment; how would you expect the sizeof operator to evaluate the size of your class if it contains an array of unknown size at compile time?
The main version works because your compiler has an extension to allow for variable length arrays. Array accesses cannot be constant expressions in C++03, even if the array and the index are both constant expressions, which is the source of the error.
The size of an array must be a constant expression. I don't believe that constant elements in an array qualify as such.
The version in main() working is probably due to a compiler extension.