B const * array[ ] in gobal

Discussion in 'C++' started by soft wind, Feb 8, 2010.

  1. soft wind

    soft wind Guest

    I have a problem about an object ( B const * array[ ] ) in global.
    Please see source program below.

    I provide B * const array [ ] in global scope in my first try,
    but their lifetime seems to be already end
    when the program goes to the enrty of main function.

    why is it so ?
    I usually provide char const * array[ ] in global and goes well.
    In which page does the standard describe about lifetime in this
    case ?
    Maybe '3.8 Object lifetime", but which phrases are applied in this
    case?

    In my second try, it goes well but another structure (class) is
    required.
    Is there any better way to provide B * pointer to handle late
    binding ?

    Thank you.

    Tsunehiko

    ------------------------------------------------------------------
    #include <string>
    #include <iostream>

    using std::string;
    using std::cout;

    class B {
    public:
    B( string str ) : str_m( str ) { }
    string get_str( void ) const { return str_m; }

    virtual int fnc( void ) const = 0;
    virtual ~B( ) { }

    private:
    std::string str_m;
    };

    class D : public B {
    public:
    D( string str ) : B( str ) { }

    virtual int fnc( void ) const { return 1; }
    };

    struct Create_B {
    string str_m;
    B * (*fnc)( string str );
    };

    B * create_D( string str )
    {
    return new D( str );
    }

    B const * list_0[ ] = {
    & D( "D0" ),
    };

    D const list_1[ ] = {
    D( "D1" ),
    };

    Create_B list_2[ ] = {
    { "D2", &create_D },
    };

    int main( void )
    {
    // My first try, but fails
    s = list_0[ 0 ]->get_str( );
    cout << s << "\n";

    // just for checking what is wrong with the first try
    string s;
    s = list_1[ 0 ].get_str( );
    cout << s << "\n";

    // My second try runs without error,
    // but another class 'Create_B' is required
    B * p = list_2[ 0 ].fnc( list_2[ 0 ].str_m );
    s = p->get_str( );
    cout << s << "\n";

    return 0;
    }
     
    soft wind, Feb 8, 2010
    #1
    1. Advertising

  2. soft wind wrote:
    > [..]
    > B const * list_0[ ] = {
    > & D( "D0" ),
    > };


    Here you initilialise the pointer (the first element of your array) with
    the address of a *temporary*. The temporary does exist at the time when
    you take its address (and since it's an object of class type, you're
    allowed to take its address), but it is destroyed at the end of this
    statement, so the address that *was* valid during initialisation is not
    valid in any other point in your program.

    > [..]


    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Feb 8, 2010
    #2
    1. Advertising

  3. soft wind

    soft wind Guest

    Victor Bazarov <> wrote:

    > but it is destroyed at the end of this
    > statement, so the address that *was* valid during initialisation is not
    > valid in any other point in your program.


    Thank you.

    Your statement is reasonable to me,
    but is it the same with this case ?

    char const * array[ ] = {
    "123",
    "ABC",
    };

    What is different between this case and my first try ?

    Tsunehiko
     
    soft wind, Feb 8, 2010
    #3
  4. soft wind wrote:
    > Victor Bazarov <> wrote:
    >
    >> but it is destroyed at the end of this
    >> statement, so the address that *was* valid during initialisation is not
    >> valid in any other point in your program.

    >
    > Thank you.
    >
    > Your statement is reasonable to me,
    > but is it the same with this case ?


    No.

    >
    > char const * array[ ] = {
    > "123",
    > "ABC",
    > };
    >
    > What is different between this case and my first try ?


    The biggest difference is that here there are no *temporaries*. The
    string literals exist from before the program starts and until the
    program finishes, and the address of the first element of each of those
    arrays (yes, each literal is itself an array) stays valid while your
    program is running.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Feb 8, 2010
    #4
  5. soft wind

    James Kanze Guest

    On Feb 8, 1:55 pm, soft wind <> wrote:
    > I have a problem about an object ( B const * array[ ] ) in
    > global. Please see source program below.


    > I provide B * const array [ ] in global scope in my first try,
    > but their lifetime seems to be already end when the program
    > goes to the enrty of main function.


    > why is it so ?
    > I usually provide char const * array[ ] in global and goes
    > well. In which page does the standard describe about
    > lifetime in this case ?
    > Maybe '3.8 Object lifetime", but which phrases are applied in this
    > case?


    > In my second try, it goes well but another structure (class)
    > is required. Is there any better way to provide B * pointer
    > to handle late binding ?


    > ------------------------------------------------------------------
    > #include <string>
    > #include <iostream>


    > using std::string;
    > using std::cout;


    > class B {
    > public:
    > B( string str ) : str_m( str ) { }
    > string get_str( void ) const { return str_m; }


    > virtual int fnc( void ) const = 0;
    > virtual ~B( ) { }


    > private:
    > std::string str_m;
    > };


    > class D : public B {
    > public:
    > D( string str ) : B( str ) { }


    > virtual int fnc( void ) const { return 1; }
    > };


    > struct Create_B {
    > string str_m;
    > B * (*fnc)( string str );
    > };


    > B * create_D( string str )
    > {
    > return new D( str );
    > }


    > B const * list_0[ ] = {
    > & D( "D0" ),


    This shouldn't compile. I don't see any user defined overload
    of D::eek:perator&, so & is the built in operator, which requires
    an lvalue.

    If it does compile, you're using an implementation specific
    extention, not C++, and you'll have to verify in the
    implementation documentation what it means with regards to
    lifetime of objects.

    (Personally, I'd be very suspicious of a compiler with such
    extensions, as it suggests that the people who wrote the
    compiler don't understand C++.)

    > };


    > D const list_1[ ] = {
    > D( "D1" ),
    > };


    > Create_B list_2[ ] = {
    > { "D2", &create_D },
    > };


    > int main( void )


    Just a nit, but the void marks you as a C programmer, and gives
    the impression that you don't know C++.

    > {
    > // My first try, but fails
    > s = list_0[ 0 ]->get_str( );


    What is "s"? I don't see it declared anywhere.

    As for the rest, see your compiler documentation; the
    initialization of list_0 isn't C++, but some compiler specific
    extention, so only the compiler documentation can tell you what
    to expect.

    > cout << s << "\n";


    > // just for checking what is wrong with the first try
    > string s;
    > s = list_1[ 0 ].get_str( );
    > cout << s << "\n";


    This is well defined behavior: it should call the get_str
    function on a copy of the D object used to initialize list_1.

    > // My second try runs without error,
    > // but another class 'Create_B' is required
    > B * p = list_2[ 0 ].fnc( list_2[ 0 ].str_m );
    > s = p->get_str( );
    > cout << s << "\n";


    This is also legal, but has distinctly different semantics than
    the first two, since it creates a new object on the heap.

    > return 0;
    > }


    --
    James Kanze
     
    James Kanze, Feb 8, 2010
    #5
  6. soft wind

    James Kanze Guest

    On Feb 8, 2:46 pm, Victor Bazarov <> wrote:
    > soft wind wrote:
    > > [..]
    > > B const * list_0[ ] = {
    > > & D( "D0" ),
    > > };


    > Here you initilialise the pointer (the first element of your
    > array) with the address of a *temporary*.


    Maybe. The code is not legal C++, and requires diagnostic. If
    he doesn't get an error message, he's not using a C++ compiler,
    but something else. And what the statement does depends on what
    that something else defines it to do.

    --
    James Kanze
     
    James Kanze, Feb 8, 2010
    #6
  7. soft wind

    soft wind Guest

    Victor Bazarov <> wrote:
    > > char const * array[ ] = {
    > >     "123",
    > >     "ABC",
    > > };

    >
    > > What is different between this case and my first try ?

    >
    > The biggest difference is that here there are no *temporaries*.  The
    > string literals exist from before the program starts and until the
    > program finishes,


    I am wondering what makes difference in general.
    I mean, In what cases is a temporary created when listed in an array
    in global scope ? Class (struct) or not ?

    How about in this case.

    D const list_1[ ] = {
    D( "D1" ),
    };

    Class object is listed in an array but seems to stay all the time.

    Tsunehiko
     
    soft wind, Feb 9, 2010
    #7
  8. soft wind

    soft wind Guest

    Victor Bazarov <> wrote:
    > > char const * array[ ] = {
    > >     "123",
    > >     "ABC",
    > > };

    >
    > > What is different between this case and my first try ?

    >
    > The biggest difference is that here there are no *temporaries*.  The
    > string literals exist from before the program starts and until the
    > program finishes,


    I am wondering what makes difference in general.
    I mean, In what cases is a temporary created when listed in an array
    in global scope ? Class (struct) or not ?

    How about in this case.

    D const list_1[ ] = {
    D( "D1" ),
    };

    Class object is listed in an array but seems to stay all the time.

    Tsunehiko
     
    soft wind, Feb 9, 2010
    #8
  9. soft wind wrote:
    > Victor Bazarov <> wrote:
    >>> char const * array[ ] = { "123", "ABC", }; What is different
    >>> between this case and my first try ?

    >> The biggest difference is that here there are no *temporaries*.
    >> The string literals exist from before the program starts and until
    >> the program finishes,

    >
    > I am wondering what makes difference in general. I mean, In what
    > cases is a temporary created when listed in an array in global scope
    > ? Class (struct) or not ?


    Any time you use the <typename> ( params(opt) ) *expression*, it creates
    a temporary. In your case <typename> == D, params == "D1".

    That expression is sometimes called "function-style cast". Even when
    you do 'int(31.15)', it creates a temporary of type 'int', which only
    lives until the full expression is evaluated or until the object is
    fully initialised (if used in the initialisation expression). The
    difference (unfortunate) for you is that you're allowed to take the
    address of a class temporary, but not of a temporary of a built-in type.

    > How about in this case.
    >
    > D const list_1[ ] = { D( "D1" ), };
    >
    > Class object is listed in an array but seems to stay all the time.


    Here you initialise *an object* with another object, which is
    copy-initialisation and is performed by the class' copy c-tor. While
    there is a temporary created, no address is taken and retained (to
    become invalid). That is, of course, if your copy c-tor does not do
    anything funny.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Feb 9, 2010
    #9
  10. soft wind

    soft wind Guest

    James Kanze <> wrote:
    > This shouldn't compile.  I don't see any user defined overload
    > of D::eek:perator&, so & is the built in operator, which requires
    > an lvalue.


    I understand your explanation but where can I find in the Standard
    why this shouldn't compile ?

    gcc version 4.0.1 and around 4.4 gave warning but created exe.
    Visual C++ 2008 Express gave no warning and error at the
    highest warning level.

    > >     // My first try, but fails
    > >     s = list_0[ 0 ]->get_str( );

    >
    > What is "s"?  I don't see it declared anywhere.


    Sorry, I exchanged the position of the code fragment
    just before posting.

    Tsunehiko
     
    soft wind, Feb 9, 2010
    #10
  11. soft wind

    James Kanze Guest

    On 9 Feb, 13:12, Victor Bazarov <> wrote:
    > soft wind wrote:


    [...]
    > That expression is sometimes called "function-style cast".
    > Even when you do 'int(31.15)', it creates a temporary of type
    > 'int', which only lives until the full expression is evaluated
    > or until the object is fully initialised (if used in the
    > initialisation expression). The difference (unfortunate) for
    > you is that you're allowed to take the address of a class
    > temporary, but not of a temporary of a built-in type.


    Only if the class overloads the address-of operator.

    --
    James Kanze
     
    James Kanze, Feb 9, 2010
    #11
  12. soft wind

    James Kanze Guest

    On 9 Feb, 13:25, soft wind <> wrote:
    > James Kanze <> wrote:


    > > This shouldn't compile. I don't see any user defined
    > > overload of D::eek:perator&, so & is the built in operator,
    > > which requires an lvalue.


    > I understand your explanation but where can I find in the
    > Standard why this shouldn't compile ?


    §5.3.1/2:

    The result of the unary & operator is a pointer to its
    operand. The operand shall be an lvalue or a
    qualifiedid. In the first case, if the type of the
    expression is "T," the type of the result is "pointer to
    T." In particular, the address of an object of type "cv
    T" is "pointer to cv T," with the same cv-qualifiers.
    For a qualified-id, if the member is a static member of
    type "T", the type of the result is plain "pointer to
    T." If the member is a nonstatic member of class C of
    type T, the type of the result is "pointer to member of
    class C of type T."


    > gcc version 4.0.1 and around 4.4 gave warning but created exe.


    A warning is a diagnostic. And are you sure you invoked g++ as
    a C++ compiler: "g++ -std=c++98", or something along those
    lines?

    > Visual C++ 2008 Express gave no warning and error at the
    > highest warning level.


    VC++ does have a number of extensions. Still, this one
    surprises me---the C++ rule is just an extension of the C rule,
    and has been that way from the very beginning.

    --
    James Kanze
     
    James Kanze, Feb 9, 2010
    #12
  13. soft wind

    soft wind Guest

    Victor Bazarov <> wrote:
    >
    > > D const list_1[ ] = { D( "D1" ), };

    >
    > > Class object is listed in an array but seems to stay all the time.

    >
    > Here you initialise *an object* with another object, which is
    > copy-initialisation and is performed by the class' copy c-tor.


    Thank you.

    My confusion clears up.

    In this case, two step operation.
    A temporary is created by ctor, then copied to initialize global
    object
    by cpoy ctor.

    Tsunehiko
     
    soft wind, Feb 10, 2010
    #13
  14. soft wind

    soft wind Guest

    James Kanze <> wrote:
    > > I understand your explanation but where can I find in the
    > > Standard why this shouldn't compile ?

    >
    > §5.3.1/2:


    Thank you.

    > A warning is a diagnostic.  And are you sure you invoked g++ as
    > a C++ compiler: "g++ -std=c++98", or something along those
    > lines?


    I invoked g++ :
    gxx -pedantic -Wall test1.cpp

    When file extension is *.cpp, gcc is invoked as a C++ compiler as a
    default.
    Right ?

    Tsunehiko
     
    soft wind, Feb 10, 2010
    #14
  15. soft wind

    James Kanze Guest

    On Feb 10, 1:49 pm, soft wind <> wrote:
    > James Kanze <> wrote:


    [...]
    > > A warning is a diagnostic. And are you sure you invoked g++
    > > as a C++ compiler: "g++ -std=c++98", or something along
    > > those lines?


    > I invoked g++ :
    > gxx -pedantic -Wall test1.cpp


    > When file extension is *.cpp, gcc is invoked as a C++ compiler
    > as a default. Right ?


    No, but I think the -pedantic flag should cause g++ to be one.
    I always use -std=c++98, but I think this is what -pedantic
    means for g++.

    --
    James Kanze
     
    James Kanze, Feb 10, 2010
    #15
    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:
    2
    Views:
    297
  2. Replies:
    11
    Views:
    1,149
  3. Javier
    Replies:
    2
    Views:
    618
    James Kanze
    Sep 4, 2007
  4. Generic Usenet Account
    Replies:
    10
    Views:
    2,340
  5. Mara Guida

    const and array of array (of array ...)

    Mara Guida, Sep 2, 2009, in forum: C Programming
    Replies:
    3
    Views:
    521
    David RF
    Sep 3, 2009
Loading...

Share This Page