declaring constant array without initializing all the elements

P

Pavan

Hi,
I need to create a consant array of larze size but however its
elements can be calculated using an equation, say for example I need
an int arry of 20 elements where each element will be

arr = 2 + (i*i)

But I want arry to be constant. How can I declare such a constant
array without actually defining all the elements?

I could think of one way:
Declare a non const arry

int arr_non_const[20];
for(int i=0; i <20; i++)
{
arr_non_const = 2 + (i*i);
}

Now declare a constant pointer

const int* arr = arr_non_const;

Is it correct? Is there any other way to do so.
 
E

Eric Pruneau

Pavan said:
Hi,
I need to create a consant array of larze size but however its
elements can be calculated using an equation, say for example I need
an int arry of 20 elements where each element will be

arr = 2 + (i*i)

But I want arry to be constant. How can I declare such a constant
array without actually defining all the elements?

I could think of one way:
Declare a non const arry

int arr_non_const[20];
for(int i=0; i <20; i++)
{
arr_non_const = 2 + (i*i);
}

Now declare a constant pointer

const int* arr = arr_non_const;

Is it correct? Is there any other way to do so.


well that code will not give you what your asking for.

I agree you cannot do somethig like

arr = 54; // error cannot assigh to a variable that is const

but you can do

int* somearray = new int[20];
arr = somearray;

you can also change the elements with arr_non_const

arr_non_const[5] = 0; // you have just changed the value of arr[5];

If arr_non_const get out of scope but not arr_non_const, I think you end up
with a pointer pointing to undefined values. So if arr_non_const get pout of
scope you cannot use arr anymore.

Now one thing you can do is

const int const_arr = [20] = { 2, 3, 6, 11, 18, ... } // you have to
explicitly initialize the array with the 20 elements

the thing to remember is when you declare something const, you have to
initialize it!

Eric
 
A

Abhishek Padmanabh

Hi,
    I need to create a consant array of larze size but however its
elements can be calculated using an equation, say for example I need
an int arry of 20 elements where each element will be

arr = 2 + (i*i)

But I want arry to be constant. How can I declare such a constant
array without actually defining all the elements?

I could think of one way:
Declare a non const arry

int arr_non_const[20];
for(int i=0; i <20; i++)
{
   arr_non_const = 2 + (i*i);

}

Now declare a constant pointer

const int* arr = arr_non_const;

Is it correct? Is there any other way to do so.


Yes, you can do it that way and expose just 'arr' to the external code
that is supposed to use that array.

You can make the arr_non_const as a global pointer initialized by a
initializer function call which holds the actual array (either static
storage duration or dynamically allocated to increase lifetime) but in
an unnamed namespace and fill it up with whatever logic you have
(initializer function). Then declare the pointer 'arr' as you have
above as a global one as well but you declare it as extern (as in C++
const variables have internal linkage), so as to be accessible in
other places.
 
L

Lionel B

Pavan said:
Hi,
I need to create a consant array of larze size but however its
elements can be calculated using an equation, say for example I need an
int arry of 20 elements where each element will be

arr = 2 + (i*i)

But I want arry to be constant. How can I declare such a constant array
without actually defining all the elements?

I could think of one way:
Declare a non const arry

int arr_non_const[20];
for(int i=0; i <20; i++)
{
arr_non_const = 2 + (i*i);
}

Now declare a constant pointer

const int* arr = arr_non_const;

Is it correct? Is there any other way to do so.


well that code will not give you what your asking for.

I agree you cannot do somethig like

arr = 54; // error cannot assigh to a variable that is const

but you can do

int* somearray = new int[20];
arr = somearray;


That's easily fixed by changing the declaration of arr to:

const int* const arr = arr_non_const;
you can also change the elements with arr_non_const

arr_non_const[5] = 0; // you have just changed the value of arr[5];

If this were all wrapped in a class then I guess you could make
arr_non_const private. But in that case, you might be better off simply
using a const member function to access the array elements.
If arr_non_const get out of scope but not arr_non_const,

I guess you meant "...but not arr,"
I think you end
up with a pointer pointing to undefined values. So if arr_non_const get
pout of scope you cannot use arr anymore.

I can't quite see how that situation might arise... array_non_const must
be defined before arr is, and at the point that you initialise arr to
arr_non_const they are (obviously) both in scope. I could see then how
arr might go out of scope before arr_non_const (which shouldn't be a
problem), but not vice-versa. Maybe I'm not thinking well, though.
Now one thing you can do is

const int const_arr = [20] = { 2, 3, 6, 11, 18, ... } // you have to
explicitly initialize the array with the 20 elements

As I understood it, the OP explicitly required that the array elements
"... be calculated using an equation", so I suspect that this would not
work for them.

One technique which might be made to work if the initialisation function
were simple/suitable, would be some template meta-programming trick,
where you get the compiler to perform the calculation, the canonical
example being a compile-time calculated factorial:

http://en.wikibooks.org/wiki/C++_Programming/Template/Template_Meta-
Programming#Example:_Compile-time_Factorial

This would be total overkill, though, I suspect.
the thing to remember is when you declare something const, you have to
initialize it!

Indeed.
 
J

James Kanze

I need to create a consant array of larze size but however its
elements can be calculated using an equation, say for example I need
an int arry of 20 elements where each element will be
arr = 2 + (i*i)

But I want arry to be constant. How can I declare such a constant
array without actually defining all the elements?

You can't. The simplest solution here is to use some sort of
custom iterator (see boost::iterators), which will allow you to
write:

std::vector< int > const arr( MyIter( 0 ), MyIter( n ) ) ;

Alternatively, you might derive, and provide a custom
constructor which does what you want.

If you need a C style array (e.g. for static initialization),
the simplest is just to write a small program which generates
the code for it. You could, however, wrap it in a struct, and
give the struct a constructor which does the initialization.
(But of course, if you do that, you loose the static
initialization, so you might as well use std::vector.)
I could think of one way: Declare a non const arry
int arr_non_const[20];
for(int i=0; i <20; i++)
{
arr_non_const = 2 + (i*i);
}

Now declare a constant pointer
const int* arr = arr_non_const;
Is it correct?

It doesn't give you a const array, just a const lvalue
expression which refers to a non-const array. Depending on the
circumstances, however, that might be enough. (In that case,
I'd probably prefer a référence:

int const (&arr)[ 20 ] = arr_non_const ;

But an std::vector still seems more appropriate in the general
case.)
 
J

James Kanze

[...]
Now one thing you can do is
const int const_arr = [20] = { 2, 3, 6, 11, 18, ... } // you have to
explicitly initialize the array with the 20 elements
As I understood it, the OP explicitly required that the array
elements "... be calculated using an equation", so I suspect
that this would not work for them.

If the equation is known at compile time, it's pretty easy to
write a program which will generate the definition of the array,
with all of its initializers. I do this a lot (although I do
remember having problems with it in one case: the array
contained a couple of million members, and the compiler wouldn't
handle it.)
One technique which might be made to work if the
initialisation function were simple/suitable, would be some
template meta-programming trick, where you get the compiler to
perform the calculation, the canonical example being a
compile-time calculated factorial:

This would be total overkill, though, I suspect.

It's a nice trick for obfuscation, but generating the code with
a separate program is a lot easier and more readable.
 
L

Lionel B

[...]
Now one thing you can do is
const int const_arr = [20] = { 2, 3, 6, 11, 18, ... } // you have to
explicitly initialize the array with the 20 elements
As I understood it, the OP explicitly required that the array elements
"... be calculated using an equation", so I suspect that this would not
work for them.

If the equation is known at compile time, it's pretty easy to write a
program which will generate the definition of the array, with all of its
initializers. I do this a lot (although I do remember having problems
with it in one case: the array contained a couple of million members,
and the compiler wouldn't handle it.)

I guess that would rule out template meta-programming too :)
Template_Meta-Programming#Example:_Compile-time_Factorial

It's a nice trick for obfuscation,

There's a rather simple solution to that: it's called "documentation".
but generating the code with a separate program is a lot easier and
more readable.

Hmm... yes, if having a whole new program to maintain (and document)
counts as "a lot easier and more readable".

On the whole I think I'd prefer the const reference array solution from
your other post; I suspect that the OP might be happy with a const lvalue
for array access.
 
J

James Kanze

[...]
Now one thing you can do is
const int const_arr = [20] = { 2, 3, 6, 11, 18, ... } // you have to
explicitly initialize the array with the 20 elements
As I understood it, the OP explicitly required that the array elements
"... be calculated using an equation", so I suspect that this would not
work for them.
If the equation is known at compile time, it's pretty easy
to write a program which will generate the definition of the
array, with all of its initializers. I do this a lot
(although I do remember having problems with it in one case:
the array contained a couple of million members, and the
compiler wouldn't handle it.)
I guess that would rule out template meta-programming too :)

It depends on the context. I use template meta-programming when
it's the simplest solution to the problem. I use an external
program to generate the code when that's the simplest solution.
Typically, the difference is when the solution requires some
internal knowledge of the C++ program: types, etc. That's only
readily available from within the compiler, so template
meta-programming is called for. Evaluating expressions like
his, however, is far more easily done in a separate program.
There's a rather simple solution to that: it's called
"documentation".

Doing things the hard way when there is a much simpler solution
is obfuscation. Regardless of the documentation. He wants each
element initialized with 2*i*i, where i is the index. Nothing
you can do in template meta-programming will be anywhere near as
clear as:
for ( int i = 0 ; i != limit ; ++ i ) {
dest << 2*i*i << ',' ;
}
Hmm... yes, if having a whole new program to maintain (and
document) counts as "a lot easier and more readable".

And your template meta-program is what, if it isn't a "whole new
program". The difference is that my new program is written in a
language designed from the start for such programs, and is
expressed simply and elegantly in a separate source file, and
not embedded somewhere in the middle of the sources for the
program it's supposed to be generating.
On the whole I think I'd prefer the const reference array
solution from your other post; I suspect that the OP might be
happy with a const lvalue for array access.

The simplest solution is probably the specialized iterators used
to initialize std::vector. Something like:

std::vector< int > v(
boost::make_transform_iterator(
boost::make_counting_iterator( 0 ), X() ),
boost::make_transform_iterator(
boost::make_counting_iterator( 10 ), X() ) ) ;

, where X is:

struct X : public std::unary_function< int, int >
{
int operator()( int i ) const { return 2*i*i ; }
} ;

(You could also write:

std::vector< int > v(
boost::make_transform_iterator(
boost::make_counting_iterator( 0 ),
boost::bind( std::multiplies< int >(), 2,
boost::bind( std::multiplies< int >(), _1,
_1 ) ) ),
boost::make_transform_iterator(
boost::make_counting_iterator( 10 ),
boost::bind( std::multiplies< int >(), 2,
boost::bind( std::multiplies< int >(), _1,
_1 ) ) ) ) ;

, without the extra class, and I suspect that boost::lambda
would work in this case as well. In the absense of a true
lambda, however, I think I'd go with the extra class.)
 
L

Lionel B

[...]
Now one thing you can do is
const int const_arr = [20] = { 2, 3, 6, 11, 18, ... } // you have
to explicitly initialize the array with the 20 elements
As I understood it, the OP explicitly required that the array
elements "... be calculated using an equation", so I suspect that
this would not work for them.
If the equation is known at compile time, it's pretty easy to write a
program which will generate the definition of the array, with all of
its initializers. I do this a lot (although I do remember having
problems with it in one case: the array contained a couple of million
members, and the compiler wouldn't handle it.)
I guess that would rule out template meta-programming too :)

It depends on the context. I use template meta-programming when it's
the simplest solution to the problem. I use an external program to
generate the code when that's the simplest solution. Typically, the
difference is when the solution requires some internal knowledge of the
C++ program: types, etc. That's only readily available from within the
compiler, so template meta-programming is called for. Evaluating
expressions like his, however, is far more easily done in a separate
program.
There's a rather simple solution to that: it's called "documentation".

Doing things the hard way when there is a much simpler solution is
obfuscation. Regardless of the documentation.

Yeah, yeah, I wasn't seriously suggesting template meta-programming as a
realistic solution here, merely pointing out that it's an option for this
type of scenario.
The simplest
!!!

solution is probably the specialized iterators used to
initialize std::vector. Something like:

std::vector< int > v(
boost::make_transform_iterator(
boost::make_counting_iterator( 0 ), X() ),
boost::make_transform_iterator(
boost::make_counting_iterator( 10 ), X() ) ) ;

, where X is:

struct X : public std::unary_function< int, int > {
int operator()( int i ) const { return 2*i*i ; }
} ;

(You could also write:

std::vector< int > v(
boost::make_transform_iterator(
boost::make_counting_iterator( 0 ),
boost::bind( std::multiplies< int >(), 2,
boost::bind( std::multiplies< int >(), _1,
_1 ) ) ),
boost::make_transform_iterator(
boost::make_counting_iterator( 10 ),
boost::bind( std::multiplies< int >(), 2,
boost::bind( std::multiplies< int >(), _1,
_1 ) ) ) ) ;

, without the extra class, and I suspect that boost::lambda would work
in this case as well. In the absense of a true lambda, however, I think
I'd go with the extra class.)

Are you serious? That (to me) is obfuscatory overkill, if not plainly
gratuitous grandstanding. Not being overly familiar with the Boost
libraries (not even part of the Standard) I'd have to go off and check
the documentation for a raft of unfamiliar functionality before having
the faintest inkling of what is going on here.

I'm not particularly averse to doing things the "right way" or using
generic coding styles - *if* there's something to be gained by it. But I
really don't believe that applies to this rather simple problem.

For me, the const reference array solution is, in this case, if not ideal
then at least *way* simpler and far more transparent in its intentions.
 
J

James Kanze

Doing things the hard way when there is a much simpler
solution is obfuscation. Regardless of the documentation.
Yeah, yeah, I wasn't seriously suggesting template
meta-programming as a realistic solution here, merely pointing
out that it's an option for this type of scenario.

OK. There are definitely cases where it's useful, but I don't
think that this is one of them.
Are you serious?

For the version with bind, not really. For the first version,
yes, if you need to evaluate the initialization values
dynamically. (Otherwise, there's nothing clearer and simpler
than a simple off-line program to generate them. Two or three
lines of AWK, perl, or whatever.)

Generally, I've used filtering and transforming iterators almost
since I started C++. One of my major complaints with the STL is
that it makes them unnecessarily awkward to implement and use.
The fact that you need two iterators with an identical type
makes even the first version wordier than it should be.
That (to me) is obfuscatory overkill, if not plainly
gratuitous grandstanding. Not being overly familiar with the
Boost libraries (not even part of the Standard) I'd have to go
off and check the documentation for a raft of unfamiliar
functionality before having the faintest inkling of what is
going on here.
I'm not particularly averse to doing things the "right way" or
using generic coding styles - *if* there's something to be
gained by it. But I really don't believe that applies to this
rather simple problem.
For me, the const reference array solution is, in this case,
if not ideal then at least *way* simpler and far more
transparent in its intentions.

A lot depends on context. It's true that something like:

struct Array
{
int data[ 10 ] ;
operator int const*() const { return data ; }
int operator[]( int i ) const { return data ; }
Array() {
for ( int i = 0 ; i < 10 ; ++ i ) {
data[ i ] = 2 * i * i ;
}
}
} ;
// ...

Array const arr ;

also has a lot to say for itself. The transform_iterator idiom,
however, is very, very general, and worth learning in its own
right.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top