Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

B const * array[ ] in gobal

0 views
Skip to first unread message

soft wind

unread,
Feb 8, 2010, 8:55:43 AM2/8/10
to
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;
}

Victor Bazarov

unread,
Feb 8, 2010, 9:46:33 AM2/8/10
to
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

soft wind

unread,
Feb 8, 2010, 10:40:55 AM2/8/10
to
Victor Bazarov <v.Abaza...@comAcast.net> 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

Victor Bazarov

unread,
Feb 8, 2010, 11:11:51 AM2/8/10
to
soft wind wrote:
> Victor Bazarov <v.Abaza...@comAcast.net> 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.

James Kanze

unread,
Feb 8, 2010, 5:55:27 PM2/8/10
to
On Feb 8, 1:55 pm, soft wind <soft_w...@nifty.com> 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::operator&, 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

unread,
Feb 8, 2010, 5:57:47 PM2/8/10
to
On Feb 8, 2:46 pm, Victor Bazarov <v.Abaza...@comAcast.net> 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

soft wind

unread,
Feb 9, 2010, 7:56:38 AM2/9/10
to
Victor Bazarov <v.Abaza...@comAcast.net> 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

unread,
Feb 9, 2010, 7:57:02 AM2/9/10
to
Victor Bazarov <v.Abaza...@comAcast.net> 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

Victor Bazarov

unread,
Feb 9, 2010, 8:12:11 AM2/9/10
to
soft wind wrote:
> Victor Bazarov <v.Abaza...@comAcast.net> 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.

soft wind

unread,
Feb 9, 2010, 8:25:56 AM2/9/10
to
James Kanze <james.ka...@gmail.com> wrote:
> This shouldn't compile.  I don't see any user defined overload
> of D::operator&, 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

James Kanze

unread,
Feb 9, 2010, 3:38:33 PM2/9/10
to
On 9 Feb, 13:12, Victor Bazarov <v.Abaza...@comAcast.net> 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

unread,
Feb 9, 2010, 3:49:58 PM2/9/10
to
On 9 Feb, 13:25, soft wind <soft_w...@nifty.com> wrote:
> James Kanze <james.ka...@gmail.com> wrote:

> > This shouldn't compile. I don't see any user defined
> > overload of D::operator&, 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

Christian Hackl

unread,
Feb 10, 2010, 7:15:56 AM2/10/10
to
soft wind ha scritto:

> James Kanze <james.ka...@gmail.com> wrote:
>> This shouldn't compile. I don't see any user defined overload
>> of D::operator&, 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.

That's because you must tell VC not to use Microsoft's language
extensions by specifying /Za. With /Za specified, you'll get the
following errors:

vc.cpp(37) : error C2102: '&' requires l-value
vc.cpp(37) : error C2466: cannot allocate an array of constant size 0


x-post & f'up to microsoft.public.vc.language


--
Christian Hackl
ha...@sbox.tugraz.at

Milano 2008/2009 -- L'Italia chiam�, s�!

soft wind

unread,
Feb 10, 2010, 8:28:00 AM2/10/10
to
Victor Bazarov <v.Abaza...@comAcast.net> 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

unread,
Feb 10, 2010, 8:49:40 AM2/10/10
to
James Kanze <james.ka...@gmail.com> 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

James Kanze

unread,
Feb 10, 2010, 5:09:59 PM2/10/10
to
On Feb 10, 1:49 pm, soft wind <soft_w...@nifty.com> wrote:
> James Kanze <james.ka...@gmail.com> 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

0 new messages