declaring constant array without initializing all the elements

Discussion in 'C++' started by Pavan, Mar 3, 2008.

  1. Pavan

    Pavan Guest

    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.
     
    Pavan, Mar 3, 2008
    #1
    1. Advertising

  2. Pavan

    Eric Pruneau Guest

    "Pavan" <> 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 = 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
     
    Eric Pruneau, Mar 3, 2008
    #2
    1. Advertising

  3. On Mar 3, 7:10 pm, Pavan <> 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 = 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.
     
    Abhishek Padmanabh, Mar 3, 2008
    #3
  4. Pavan

    Lionel B Guest

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

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

    --
    Lionel B
     
    Lionel B, Mar 3, 2008
    #4
  5. Pavan

    James Kanze Guest

    On Mar 3, 3:10 pm, Pavan <> 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 = 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.)

    --
    James Kanze (GABI Software) email:
    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, Mar 4, 2008
    #5
  6. Pavan

    James Kanze Guest

    On Mar 3, 4:30 pm, Lionel B <> 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++_Programming/Template/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:
    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, Mar 4, 2008
    #6
  7. Pavan

    Lionel B Guest

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

    > On Mar 3, 4:30 pm, Lionel B <> 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++_Programming/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
    > 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.

    --
    Lionel B
     
    Lionel B, Mar 4, 2008
    #7
  8. Pavan

    James Kanze Guest

    On Mar 4, 11:09 am, Lionel B <> wrote:
    > On Tue, 04 Mar 2008 00:39:50 -0800, James Kanze wrote:
    > > On Mar 3, 4:30 pm, Lionel B <> 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++_Programming/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:
    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, Mar 4, 2008
    #8
  9. Pavan

    Lionel B Guest

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

    > On Mar 4, 11:09 am, Lionel B <> wrote:
    >> On Tue, 04 Mar 2008 00:39:50 -0800, James Kanze wrote:
    >> > On Mar 3, 4:30 pm, Lionel B <> 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++_Programming/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
     
    Lionel B, Mar 4, 2008
    #9
  10. Pavan

    James Kanze Guest

    On 4 mar, 14:16, Lionel B <> wrote:
    > On Tue, 04 Mar 2008 04:37:29 -0800, James Kanze wrote:
    > > On Mar 4, 11:09 am, Lionel B <> wrote:
    > >> On Tue, 04 Mar 2008 00:39:50 -0800, James Kanze wrote:
    > >> > On Mar 3, 4:30 pm, Lionel B <> 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 ; }
    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:
    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, Mar 4, 2008
    #10
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    3
    Views:
    9,351
    =?ISO-8859-2?Q?Mateusz_=A3oskot?=
    Jul 31, 2004
  2. Replies:
    13
    Views:
    12,956
    Kai-Uwe Bux
    Jan 22, 2007
  3. Replies:
    1
    Views:
    370
    Victor Bazarov
    Nov 6, 2007
  4. Fredxx
    Replies:
    3
    Views:
    651
    Martin Thompson
    Jul 15, 2009
  5. SM
    Replies:
    8
    Views:
    158
    -Lost
    May 1, 2007
Loading...

Share This Page