Velocity Reviews > C++ > declaring constant array without initializing all the elements

declaring constant array without initializing all the elements

Pavan
Guest
Posts: n/a

 03-03-2008
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[i] = 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[i] = 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.

Eric Pruneau
Guest
Posts: n/a

 03-03-2008

"Pavan" <(E-Mail Removed)> a écrit dans le message de news:
> 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[i] = 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[i] = 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[i] = 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

Guest
Posts: n/a

 03-03-2008
On Mar 3, 7:10*pm, Pavan <(E-Mail Removed)> wrote:
> 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[i] = 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[i] = 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.

Lionel B
Guest
Posts: n/a

 03-03-2008
On Mon, 03 Mar 2008 09:46:35 -0500, Eric Pruneau wrote:

> "Pavan" <(E-Mail Removed)> a Ã©crit dans le message de news:
>> 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[i] = 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[i] = 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[i] = 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%2B%2B...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.

--
Lionel B

James Kanze
Guest
Posts: n/a

 03-04-2008
On Mar 3, 3:10 pm, Pavan <(E-Mail Removed)> wrote:

> 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[i] = 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[i] = 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.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

James Kanze
Guest
Posts: n/a

 03-04-2008
On Mar 3, 4:30 pm, Lionel B <(E-Mail Removed)> wrote:

[...]
> > 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:

> http://en.wikibooks.org/wiki/C%2B%2B...Template_Meta-
> Programming#Example:_Compile-time_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.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Lionel B
Guest
Posts: n/a

 03-04-2008
On Tue, 04 Mar 2008 00:39:50 -0800, James Kanze wrote:

> On Mar 3, 4:30 pm, Lionel B <(E-Mail Removed)> wrote:
>
> [...]
>> > 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

>> 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%2B%2B...ming/Template/

Template_Meta-Programming#Example:_Compile-time_Factorial
>
>> This would be total overkill, though, I suspect.

>
> 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

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.

--
Lionel B

James Kanze
Guest
Posts: n/a

 03-04-2008
On Mar 4, 11:09 am, Lionel B <(E-Mail Removed)> wrote:
> On Tue, 04 Mar 2008 00:39:50 -0800, James Kanze wrote:
> > On Mar 3, 4:30 pm, Lionel B <(E-Mail Removed)> wrote:

> > [...]
> >> > 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.

> >> 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%2B%2B...ming/Template/

> Template_Meta-Programming#Example:_Compile-time_Factorial

> >> This would be total overkill, though, I suspect.

> > It's a nice trick for obfuscation,

> 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 << ',' ;
}

> > 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".

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.)

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Lionel B
Guest
Posts: n/a

 03-04-2008
On Tue, 04 Mar 2008 04:37:29 -0800, James Kanze wrote:

> On Mar 4, 11:09 am, Lionel B <(E-Mail Removed)> wrote:
>> On Tue, 04 Mar 2008 00:39:50 -0800, James Kanze wrote:
>> > On Mar 3, 4:30 pm, Lionel B <(E-Mail Removed)> wrote:

>
>> > [...]
>> >> > 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.
>
>> >> 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%2B%2B...ming/Template/

>
>> Template_Meta-Programming#Example:_Compile-time_Factorial

>
>> >> This would be total overkill, though, I suspect.

>
>> > It's a nice trick for obfuscation,

>
>> 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.

>> 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.)

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.

--
Lionel B

James Kanze
Guest
Posts: n/a

 03-04-2008
On 4 mar, 14:16, Lionel B <(E-Mail Removed)> wrote:
> On Tue, 04 Mar 2008 04:37:29 -0800, James Kanze wrote:
> > On Mar 4, 11:09 am, Lionel B <(E-Mail Removed)> wrote:
> >> On Tue, 04 Mar 2008 00:39:50 -0800, James Kanze wrote:
> >> > On Mar 3, 4:30 pm, Lionel B <(E-Mail Removed)> wrote:

>
> >> > [...]

> > 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.

> >> 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.)

> 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[i] ; }
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.

--
James Kanze (GABI Software) email:(E-Mail Removed)
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34