how to computinally initialize a const array(make const look-up-tables)? - c++

Background: I'm stuck to arm-arago-linux-gnueabi-g++ (GCC) 4.3.3. Although answers that requires C++11 or later is also appreciated, please explicitly express any language requirement later than C++03.
The object's constructor fills values into tables to be used by the algorithm.
As those table does not change and are not supposed to be changed, I want the them to be const, how do I do that?
Difficulty #1, the values are computationally generated, and I don't want to hard code them in a source file.
Difficulty #2, the computing sometimes depends on inputs that are only available at runtime.
Difficulty #3, I don't know why but I don't want the array to be static, even though the values might be the same for all objects(cases where the values does not depend on runtime input).
Difficulty #4, it's an array, so initializer list in C++03 won't work.
Edit1:
A few weeks after this post, I found both std::array and std::vector are very good alternative to C-style array when std::array is not available.

You can encapsulate the tables in a private type, with a single const instance of that type in your object, then forward the relevant constructor parameters to the private object; this works because even a const object is non-const during its construction.
For example:
class MyClass {
const struct Tables {
double x[1000];
double y[200];
Tables(int i, double d) {
x[i] = d;
y[200 - i] = -d;
}
} tables;
public:
MyClass(int i, double d) : tables(i, d) {}
};
MyClass c(20, 5.5);
Another technique is to build the tables in an ephemeral mutable array whose lifetime is bounded by the lifetime of the constructor, then initialize the const array from those mutable arrays.
Using C++11 std::array (since array types can't be copy-initialized):
class MyClass {
static std::array<double, 1000> buildArray(...) {
std::array<double, 1000> array;
... // fill array
return array;
}
const std::array<double, 1000> mArray;
public:
MyClass(...) : mArray(buildArray(...)) {}
};
Note that std::array is easy to express in C++03; it doesn't depend on any C++11 language features.
If you're worried about the overhead of returning a large array, instrument it - even C++03 compilers are capable of optimising large array returns.

I think you could implement a class containing the actual non const array. That way you can easily compute the values in a constructor.
Then this class would only have to implement the operator[] to be usable as an array. Or it could also simply return a const reference to the array.
Implementation example :
#include <iostream>
using namespace std;
class const_array {
int *arr;
size_t size;
public:
const_array(size_t size, int typ): size(size) {
arr = new int[size];
size_t i;
int val = 0;
for (i=0; i<size; i++) {
val += typ;
arr[i] = val;
}
}
const_array(const const_array & src): size(src.size) {
arr = new int[size];
size_t i;
for (i=0; i<size; i++) {
arr[i] = src.arr[i];
}
}
~const_array() {
delete[] arr;
}
const int * const getArray() const {
return arr;
}
int getSize() const {
return size;
}
const int& operator[](int i) {
return arr[i];
}
};
int main() {
const_array a(16, 4);
// int *arr = a.getArray(); error
const int *arr = a.getArray();
int j = a[2];
int k = arr[2];
// int * pj = &(a[2]); error
const int * pj = &(a[2]);
const int * pk = &(arr[2]);
cout << "a[2]=" << j << " (" << pj << ") - a.getArray[2]="
<< j << " (" << pj << ")" << endl;
return 0;
}

Related

How do I create an std::array of immutable structs? I.e. structs with only const values [duplicate]

This question already has answers here:
Initialize an std::array algorithmically at compile time
(3 answers)
Populate An Array Using Constexpr at Compile-time
(4 answers)
Initialize array whose size is a compile-time constant to single value
(3 answers)
Closed 4 months ago.
This post was edited and submitted for review 4 months ago and failed to reopen the post:
Original close reason(s) were not resolved
Say I have struct S:
struct S {
const int i;
const bool b;
}
And I want to create an (non-const) array of this struct like so:
std::array<S, 16> arr;
for(int i = 0; i<arr.size(); i++)
arr[i] = { i, i%2==0 };
Then the compiler will complain that I didn't initialize the a const variable when I initialized the array.
I tried doing it with a vector as an intermediary. But int the function I'm writing I have to pass the original array in another struct, and return that other struct.
struct OtherStruct {
const std::array<S,16> sArray;
};
OtherStruct f() {
std::vector<S> vec(16);
for(int i = 0; i<16; i++)
vec.push_back({ i, i%2==0 });
return { vec.data() };
}
But that didn't work either. I hoped that passing the pointer to the vector data would be cast into a C-style array, from which an std::array could be made. What is the cleanest way to fix this?
I'm working with C++11.
Note that this example is a gross simplification. The line arr[i] = { i, i%2==0 }; would be replaced by a function that parses incoming network data. The actual array is way bigger and the struct is also more complicated. None of the data that will populate the struct will be known at compile time, only the layout.
You can use parameter pack expansion to create an initialiser list of arbitrary size.
You will need to backport std::index_sequence into C++11
template <size_t... Is>
std::array<S, sizeof...(Is)> make_s_array_impl(index_sequence<Is...>) {
return { { { Is, Is % 2 == 0 }... } };
}
template <size_t N>
std::array<S, N> make_s_array()
{
return make_s_array_impl(make_index_sequence<N>{});
}
See it live
As the number of values is known in the compile time, you can fill the array with an initializer list. You can create it easily with BOOST_PP_REPEAT:
#include <boost/preprocessor/repetition/repeat.hpp>
struct S {
const int i;
const bool b;
};
struct OtherStruct {
const std::array<S,16> sArray;
};
OtherStruct f() {
#define FILL(z, i, ignored) { i, i%2==0 },
return {std::array<S,16>{{
BOOST_PP_REPEAT(16, FILL, ignored)
}}};
#undef FILL
}
In C/C++ when you use the const keyword you cannot left the variable uninitialized when you declare it and neither assign a new value after this is declared.
For example:
const int i = 5; //this is a correct way to use the const keyword
const int i;
...
i = 5; //this is NOT a correct way to use the const keyword
However, you can use const_cast<T> to bind a pointer of the same type to the value of your struct instance and change it only once in the for loop.
In this way you can obtain what you asked.
#include <iostream>
#include <array>
struct S{
const bool b = 0; //Intialize the values in order to avoid compiler errors.
const int i = 0;
};
int main(){
std::array<struct S, 16> arr;
for(int i = 0; i<arr.size(); i++){
// declare a variable that point to the const value of your struct instance.
bool* b = const_cast <bool*> (&arr[i].b);
int* in = const_cast <int*> (&arr[i].i);
*b = i; //change the value with the value you need.
*in = i%2==0;
}
for(int i = 0; i<arr.size(); i++){
int a = i%2==0;
std::cout<< "const bool: " << arr[i].b << " " << (bool)i << "const int: " << arr[i].i << " " << a << std::endl;
}
}

Rewrite This Malloc Using New For 2D Array

After some trial and error I found a way to malloc a 2D array so it is contiguous in memory, equivalent to the non-dynamic case.
int numRows =2;
int numCols = 4;
int (*p)[numCols];
p = (int (*)[numCols]) malloc(sizeof(int)*numRows*numCols);
So p is now basically the same as if I had done int p[2][4] - except it's on the heap instead of the stack.
2 Questions:
Do I just need to call free(p) to free the memory? No looping?
How would I convert this to using new, instead of malloc?
I tried
p = new (int (*)[4])[2];
But that gave the error:
error: cannot convert int (**)[4] to int (*)[4] in assignment
Here's a class template that uses one std::vector to hold a contiguous buffer, and size-aware proxy objects to access array elements dimension-by-dimension:
template<typename T>
class TwoDArray {
private:
std::size_t n_rows;
std::size_t n_cols;
std::vector<T> buf;
public:
class OneDArrayProxy {
private:
T *rowptr;
std::size_t colsize;
public:
OneDArrayProxy(const T *rp, std::size_t cs) : rowptr(const_cast<T *>(rp)), colsize(cs) {}
T const &operator[](std::size_t index) const {
return rowptr[index];
}
T &operator[](std::size_t index) {
return rowptr[index];
}
std::size_t size() const { return colsize; }
};
TwoDArray(std::size_t rows, std::size_t cols) : n_rows(rows), n_cols(cols), buf(rows * cols) {}
TwoDArray() : TwoDArray(0, 0) {}
OneDArrayProxy operator[](std::size_t index) const {
return OneDArrayProxy(&buf[index * n_cols], n_cols);
}
std::size_t rows() const { return n_rows; }
std::size_t columns() const { return n_cols; }
};
Usage example:
int main()
{
TwoDArray<int> arr(9, 5);
for (std::size_t i = 0; i < arr.rows(); i++) {
for (std::size_t j = 0; j < arr.columns(); j++) {
arr[i][j] = i * 10 + j;
}
}
for (std::size_t i = 0; i < arr.rows(); i++) {
// you can use the array element's 'size()' function instead of 'columns()'
for (std::size_t j = 0; j < arr[i].size(); j++) {
std::cout << arr[i][j] << " ";
}
std::cout << std::endl;
}
}
You can't do that in C++. Your malloc() code is perfectly valid C, but not valid C++. And it won't work with new.
C++ requires array types to have constant size, C allows arrays types of dynamic size. There is only an exception for 1D arrays, which may be allocated with dynamic size in C++, but that's it. In a 2D array, the second size must be known at compile time.
This is the one point at which C is much more powerful than C++.
It takes a bit to convince g++ to follow the standard in this regard, but compiling this little program
#include <stdlib.h>
int main(int argc, char** args) {
int (*foo)[argc];
}
with g++ -pedantic -std=c++11 foo.cpp dutifully produces the error message:
foo.cpp: In function ‘int main(int, char**)’:
foo.cpp:4:17: warning: ISO C++ forbids variable length array ‘foo’ [-Wvla]
1) Yes, you could just call free()
But attention, you are doing pointer aliasing (2 pointers to different types, int and int[] with the same address), which can cause subtle optimisation bugs. And in C++ it's a very bad practice to use malloc(), and numcols should be const.
2) The way you can do this in C++ would be to use [<array>][2] if the size to be known at compile time:
array<array<int, 4>,2> a;
The more flexible alternative is to use vectors which allow for dynamic size and resizing:
vector <vector <int>> b(2, vector<int>(4));
3) With new you could also do :
p = new (int[2][4]);
The first dimension could also be variable, but the second has to be a constant. But I'd encourage you to use one of the standard containter alternative.

Multidimensional array: operator overloading

I have a class with a multidimensional array:
it is possible to create a one, two, ..., n dimensional array with this class
if the array has n dimensions, i want to use n operator[] to get an object:
example:
A a({2,2,2,2}];
a[0][1][1][0] = 5;
but array is not a vector of pointer which lead to other vectors etc...
so i want the operator[] to return a class object until the last dimension, then return a integer
This is a strongly simplified code, but it shows my problem:
The error i receive: "[Error] cannot convert 'A::B' to 'int' in initialization"
#include <cstddef> // nullptr_t, ptrdiff_t, size_t
#include <iostream> // cin, cout...
class A {
private:
static int* a;
public:
static int dimensions;
A(int i=0) {
dimensions = i;
a = new int[5];
for(int j=0; j<5; j++) a[j]=j;
};
class B{
public:
B operator[](std::ptrdiff_t);
};
class C: public B{
public:
int& operator[](std::ptrdiff_t);
};
B operator[](std::ptrdiff_t);
};
//int A::count = 0;
A::B A::operator[] (std::ptrdiff_t i) {
B res;
if (dimensions <= 1){
res = C();
}
else{
res = B();
}
dimensions--;
return res;
}
A::B A::B::operator[] (std::ptrdiff_t i){
B res;
if (dimensions <=1){
res = B();
}
else{
res = C();
}
dimensions--;
return res;
}
int& A::C::operator[](std::ptrdiff_t i){
return *(a+i);
}
int main(){
A* obj = new A(5);
int res = obj[1][1][1][1][1];
std::cout<< res << std::endl;
}
The operator[] is evaluated from left to right in obj[1][1]...[1], so obj[1] returns a B object. Suppose now you just have int res = obj[1], then you'll assign to a B object (or C object in the case of multiple invocations of []) an int, but there is no conversion from B or C to int. You probably need to write a conversion operator, like
operator int()
{
// convert to int here
}
for A, B and C, as overloaded operators are not inherited.
I got rid of your compiling error just by writing such operators for A and B (of course I have linking errors since there are un-defined functions).
Also, note that if you want to write something like obj[1][1]...[1] = 10, you need to overload operator=, as again there is no implicit conversion from int to A or your proxy objects.
Hope this makes sense.
PS: see also #Oncaphillis' comment!
vsoftco is totally right, you need to implement an overload operator if you want to actually access your elements. This is necessary if you want it to be dynamic, which is how you describe it. I actually thought this was an interesting problem, so I implemented what you described as a template. I think it works, but a few things might be slightly off. Here's the code:
template<typename T>
class nDimArray {
using thisT = nDimArray<T>;
T m_value;
std::vector<thisT*> m_children;
public:
nDimArray(std::vector<T> sizes) {
assert(sizes.size() != 0);
int thisSize = sizes[sizes.size() - 1];
sizes.pop_back();
m_children.resize(thisSize);
if(sizes.size() == 0) {
//initialize elements
for(auto &c : m_children) {
c = new nDimArray(T(0));
}
} else {
//initialize children
for(auto &c : m_children) {
c = new nDimArray(sizes);
}
}
}
~nDimArray() {
for(auto &c : m_children) {
delete c;
}
}
nDimArray<T> &operator[](const unsigned int index) {
assert(!isElement());
assert(index < m_children.size());
return *m_children[index];
}
//icky dynamic cast operators
operator T() {
assert(isElement());
return m_value;
}
T &operator=(T value) {
assert(isElement());
m_value = value;
return m_value;
}
private:
nDimArray(T value) {
m_value = value;
}
bool isElement() const {
return m_children.size() == 0;
}
//no implementation yet
nDimArray(const nDimArray&);
nDimArray&operator=(const nDimArray&);
};
The basic idea is that this class can either act as an array of arrays, or an element. That means that in fact an array of arrays COULD be an array of elements! When you want to get a value, it tries to cast it to an element, and if that doesn't work, it just throws an assertion error.
Hopefully it makes sense, and of course if you have any questions ask away! In fact, I hope you do ask because the scope of the problem you describe is greater than you probably think it is.
It could be fun to use a Russian-doll style template class for this.
// general template where 'd' indicates the number of dimensions of the container
// and 'n' indicates the length of each dimension
// with a bit more template magic, we could probably support each
// dimension being able to have it's own size
template<size_t d, size_t n>
class foo
{
private:
foo<d-1, n> data[n];
public:
foo<d-1, n>& operator[](std::ptrdiff_t x)
{
return data[x];
}
};
// a specialization for one dimension. n can still specify the length
template<size_t n>
class foo<1, n>
{
private:
int data[n];
public:
int& operator[](std::ptrdiff_t x)
{
return data[x];
}
};
int main(int argc, char** argv)
{
foo<3, 10> myFoo;
for(int i=0; i<10; ++i)
for(int j=0; j<10; ++j)
for(int k=0; k<10; ++k)
myFoo[i][j][k] = i*10000 + j*100 + k;
return myFoo[9][9][9]; // would be 090909 in this case
}
Each dimension keeps an array of previous-dimension elements. Dimension 1 uses the base specialization that tracks a 1D int array. Dimension 2 would then keep an array of one-dimentional arrays, D3 would have an array of two-dimensional arrays, etc. Then access looks the same as native multi-dimensional arrays. I'm using arrays inside the class in my example. This makes all the memory contiguous for the n-dimensional arrays, and doesn't require dynamic allocations inside the class. However, you could provide the same functionality with dynamic allocation as well.

C++ Operator Overload Error

I'm trying to create my own version of an array called a safearray, to test my knowledge of operator overloading and creating proper class's and such.
I'm encountering two errors.
SafeArray.h:11:15: error: ‘const int SafeArray::operator’ cannot be overloaded
SafeArray.h:10:10: error: with ‘int& SafeArray::operator’
My code is split between three files.
Main.cpp
#include <cstdlib>
#include <iostream>
#include "SafeArray.h"
using namespace std;
int main(int argc, char** argv) {
SafeArray a(10); // 10 integer elements
for (int i = 0; i < a.length(); i++) {
cout << i << " " << a[i] << "s" << endl; // values initialise to 0
}
cout << endl << a[1]; // Program exits here.
a[3] = 42;
cout << a[3];
a[10] = 10;
cout << a[10];
a[-1] = -1; // out-of-bounds is "safe"?
SafeArray b(20); // another array
b = a; // array assignment
for (int i = 0; i < b.length(); i++) {
cout << b[i] << endl; // values copied from a
}
return 0;
}
SafeArray.h
#ifndef SAFEARRAY_H
#define SAFEARRAY_H
class SafeArray {
public:
SafeArray(int); // int variable will be the array size
int length();
int boundsCheck(int y); // constructor will call this function
// const SafeArray operator= (const SafeArray&);
int& operator[] (int y);
const int operator [] (const int y); // you need this one too.
SafeArray &operator=(SafeArray rhs) {
std::swap(array, rhs.array);
std::swap(length_, rhs.length_);
}
SafeArray(SafeArray const &other);
~SafeArray();
private:
int length_;
int *array;
//int array[];
};
#endif /* SAFEARRAY_H */
SafeArray.cpp
#include "SafeArray.h"
#include <iostream>
SafeArray::SafeArray(int x) {
length_ = x;
array = new int[length];
for (int i = 0; i < length_; i++) {
array[i] = 0;
}
}
int SafeArray::length() {
return this->length_;
}
int SafeArray::boundsCheck(int y) {
}
int& SafeArray::operator[] (int y) {
return array[y];
}
SafeArray::~SafeArray() {
delete [] array;
}
SafeArray::SafeArray(SafeArray const &other) {
int *temp = new int[rhs.size_];
for (int i=0; i<rhs.size_; i++)
temp[i] = rhs.array[i];
std::swap(temp, array);
delete [] temp;
return *this;
}
Your class definition isn't valid. int array[] is an incomplete type, which must not appear as a (non-static) class member. Some compilers accept this as a synonym for int array[0], but zero-sized arrays are not valid in C++, either (only in C99).
In short, you cannot write your code the way you do. You need to learn about dynamic allocation and manage your own memory. Check out how std::vector is implemented.
In C++11, I might recommend a std::unique_ptr<int[]> array as a quick-fix approach, to be initialized as array(new int[x]).
Actually int array[] is valid, and may appear as a class member. The following compiles with strict C++11 conformance:
class foo
{
public:
foo() {}
int length;
int A[];
};
void ralph()
{
foo *bar = (foo *)new int[ 21 ];
bar->length = 20;
bar->A[0] = 1;
}
This is legal, and has its advantages (occasionally). Although it is not commonly used.
However, I suspect that the OP wanted something more along the lines of
class SafeArray {
public:
SafeArray(int); // int variable will be the array size
int length();
int boundsCheck(int y); // constructor will call this function
int& operator[] (int y);
const int operator [] (const int y) // you need this one too.
private:
int length_;
int *array;
};
along with
SafeArray::SafeArray(int x) {
length_ = x;
array = new int[length];
for (int i = 0; i < length_; i++) {
array[i] = 0;
}
}
As #Kerrek already pointed out, your class definition is clearly wrong (shouldn't compile).
To fix it, you want to change the definition to something like:
int *array;
Then in your default ctor you could use something like this:
SafeArray::SafeArray(unsigned size = 0)
: array(new int[size])
{
for (unsigned i=0; i<size; i++)
array[i] = 0;
}
Then, yes, you'll need to write an assignment operator. The usual way is called the copy and swap idiom. You create a copy, then swap the contents of the current one with those of the copy:
SafeArray &operator=(SafeArray rhs) {
std::swap(array, rhs.array);
std::swap(length_, rhs.length_);
}
Along with that, you'll need a copy constructor that makes a copy of the data as well:
SafeArray::SafeArray(SafeArray const &other) {
int *temp = new int[rhs.size_];
for (int i=0; i<rhs.size_; i++)
temp[i] = rhs.array[i];
std::swap(temp, array);
delete [] temp;
return *this;
}
Finally, you'll need a destructor to destroy an object and (particularly) delete the memory it holds:
SafeArray::~SafeArray() {
delete [] array;
}
Then realize that all of that is an ugly mess that will never really work well. In particular, the basic methodology is restricted to an array that's basically fixed in size. As long as you only store ints, it's fairly easy to overlook the problems, and make a dynamic array that (sort of) works. When/if you want to store some other type, however, you just about need to separate allocating memory from initializing objects in that memory, which means throwing away essentially all the code above, and replacing it with something that:
keeps track of the array size and allocation size separately
allocates memory with ::operator new, an Allocator object, or something else similar
uses placement new to initialize objects in the memory when needed.
uses explicit destructor calls to destroy the objects
uses ::operator delete to release memory
and so on. To summarize, std::vector is not a trivial piece of work.
The error message refers to these two lines:
int& operator[] (int y);
const int operator [] (const int y); // you need this one too.
Your error message says that (int y) and (const int y) are too similar to be two different overloads of the [] operator. You cannot overload on (int y) and (const int y) because the calls would all be ambiguous.
You probably meant to return a const int if your SafeArray is const, but return an int& if your SafeArray is not const. In that case, you declare the second function to apply to const SafeArray, by putting the word const after the parameter list. This is what you should write in SafeArray.h:
int& operator[] (int y);
const int operator [] (int y) const; // you need this one too.
You would then have to write both of these functions in SafeArray.cpp:
int& SafeArray::operator[] (int y) {
return array[y];
}
const int SafeArray::operator[] (int y) const { // you need this one too.
return array[y];
}

initialize a const array in a class initializer in C++

I have the following class in C++:
class a {
const int b[2];
// other stuff follows
// and here's the constructor
a(void);
}
The question is, how do I initialize b in the initialization list, given that I can't initialize it inside the body of the function of the constructor, because b is const?
This doesn't work:
a::a(void) :
b([2,3])
{
// other initialization stuff
}
Edit: The case in point is when I can have different values for b for different instances, but the values are known to be constant for the lifetime of the instance.
With C++11 the answer to this question has now changed and you can in fact do:
struct a {
const int b[2];
// other bits follow
// and here's the constructor
a();
};
a::a() :
b{2,3}
{
// other constructor work
}
int main() {
a a;
}
Like the others said, ISO C++ doesn't support that. But you can workaround it. Just use std::vector instead.
int* a = new int[N];
// fill a
class C {
const std::vector<int> v;
public:
C():v(a, a+N) {}
};
It is not possible in the current standard. I believe you'll be able to do this in C++0x using initializer lists (see A Brief Look at C++0x, by Bjarne Stroustrup, for more information about initializer lists and other nice C++0x features).
std::vector uses the heap. Geez, what a waste that would be just for the sake of a const sanity-check. The point of std::vector is dynamic growth at run-time, not any old syntax checking that should be done at compile-time. If you're not going to grow then create a class to wrap a normal array.
#include <stdio.h>
template <class Type, size_t MaxLength>
class ConstFixedSizeArrayFiller {
private:
size_t length;
public:
ConstFixedSizeArrayFiller() : length(0) {
}
virtual ~ConstFixedSizeArrayFiller() {
}
virtual void Fill(Type *array) = 0;
protected:
void add_element(Type *array, const Type & element)
{
if(length >= MaxLength) {
// todo: throw more appropriate out-of-bounds exception
throw 0;
}
array[length] = element;
length++;
}
};
template <class Type, size_t Length>
class ConstFixedSizeArray {
private:
Type array[Length];
public:
explicit ConstFixedSizeArray(
ConstFixedSizeArrayFiller<Type, Length> & filler
) {
filler.Fill(array);
}
const Type *Array() const {
return array;
}
size_t ArrayLength() const {
return Length;
}
};
class a {
private:
class b_filler : public ConstFixedSizeArrayFiller<int, 2> {
public:
virtual ~b_filler() {
}
virtual void Fill(int *array) {
add_element(array, 87);
add_element(array, 96);
}
};
const ConstFixedSizeArray<int, 2> b;
public:
a(void) : b(b_filler()) {
}
void print_items() {
size_t i;
for(i = 0; i < b.ArrayLength(); i++)
{
printf("%d\n", b.Array()[i]);
}
}
};
int main()
{
a x;
x.print_items();
return 0;
}
ConstFixedSizeArrayFiller and ConstFixedSizeArray are reusable.
The first allows run-time bounds checking while initializing the array (same as a vector might), which can later become const after this initialization.
The second allows the array to be allocated inside another object, which could be on the heap or simply the stack if that's where the object is. There's no waste of time allocating from the heap. It also performs compile-time const checking on the array.
b_filler is a tiny private class to provide the initialization values. The size of the array is checked at compile-time with the template arguments, so there's no chance of going out of bounds.
I'm sure there are more exotic ways to modify this. This is an initial stab. I think you can pretty much make up for any of the compiler's shortcoming with classes.
ISO standard C++ doesn't let you do this. If it did, the syntax would probably be:
a::a(void) :
b({2,3})
{
// other initialization stuff
}
Or something along those lines. From your question it actually sounds like what you want is a constant class (aka static) member that is the array. C++ does let you do this. Like so:
#include <iostream>
class A
{
public:
A();
static const int a[2];
};
const int A::a[2] = {0, 1};
A::A()
{
}
int main (int argc, char * const argv[])
{
std::cout << "A::a => " << A::a[0] << ", " << A::a[1] << "\n";
return 0;
}
The output being:
A::a => 0, 1
Now of course since this is a static class member it is the same for every instance of class A. If that is not what you want, ie you want each instance of A to have different element values in the array a then you're making the mistake of trying to make the array const to begin with. You should just be doing this:
#include <iostream>
class A
{
public:
A();
int a[2];
};
A::A()
{
a[0] = 9; // or some calculation
a[1] = 10; // or some calculation
}
int main (int argc, char * const argv[])
{
A v;
std::cout << "v.a => " << v.a[0] << ", " << v.a[1] << "\n";
return 0;
}
Where I've a constant array, it's always been done as static. If you can accept that, this code should compile and run.
#include <stdio.h>
#include <stdlib.h>
class a {
static const int b[2];
public:
a(void) {
for(int i = 0; i < 2; i++) {
printf("b[%d] = [%d]\n", i, b[i]);
}
}
};
const int a::b[2] = { 4, 2 };
int main(int argc, char **argv)
{
a foo;
return 0;
}
You can't do that from the initialization list,
Have a look at this:
http://www.cprogramming.com/tutorial/initialization-lists-c++.html
:)
A solution without using the heap with std::vector is to use boost::array, though you can't initialize array members directly in the constructor.
#include <boost/array.hpp>
const boost::array<int, 2> aa={ { 2, 3} };
class A {
const boost::array<int, 2> b;
A():b(aa){};
};
How about emulating a const array via an accessor function? It's non-static (as you requested), and it doesn't require stl or any other library:
class a {
int privateB[2];
public:
a(int b0,b1) { privateB[0]=b0; privateB[1]=b1; }
int b(const int idx) { return privateB[idx]; }
}
Because a::privateB is private, it is effectively constant outside a::, and you can access it similar to an array, e.g.
a aobj(2,3); // initialize "constant array" b[]
n = aobj.b(1); // read b[1] (write impossible from here)
If you are willing to use a pair of classes, you could additionally protect privateB from member functions. This could be done by inheriting a; but I think I prefer John Harrison's comp.lang.c++ post using a const class.
interestingly, in C# you have the keyword const that translates to C++'s static const, as opposed to readonly which can be only set at constructors and initializations, even by non-constants, ex:
readonly DateTime a = DateTime.Now;
I agree, if you have a const pre-defined array you might as well make it static.
At that point you can use this interesting syntax:
//in header file
class a{
static const int SIZE;
static const char array[][10];
};
//in cpp file:
const int a::SIZE = 5;
const char array[SIZE][10] = {"hello", "cruel","world","goodbye", "!"};
however, I did not find a way around the constant '10'. The reason is clear though, it needs it to know how to perform accessing to the array. A possible alternative is to use #define, but I dislike that method and I #undef at the end of the header, with a comment to edit there at CPP as well in case if a change.