B const * array[ ] in gobal

S

soft wind

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;
}
 
V

Victor Bazarov

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

soft wind

Victor Bazarov said:
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
 
V

Victor Bazarov

soft said:
Victor Bazarov said:
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
 
J

James Kanze

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

James Kanze

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

soft wind

Victor Bazarov said:
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
 
S

soft wind

Victor Bazarov said:
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
 
V

Victor Bazarov

soft said:
Victor Bazarov said:
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
 
S

soft wind

James Kanze said:
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
 
J

James Kanze

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

James Kanze

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

soft wind

Victor Bazarov said:
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
 
S

soft wind

James Kanze said:
§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
 

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,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top