anonymous array of strings // ("taking address of temporary"- how long is temporary valid?)

A

anon.asdf

Hello!

1) ===============================
When trying to define an array of std::string ...

func( (std::string []) { std::string("ab"), std::string("cd"),
std::string("ef") } , 3 );

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
....g++ tells me: "invalid use of non-lvalue array"
Can the above be modified to work?

void func(std::string arr[], int n)
{
while ((--n) >= 0) {
std::cout << arr[n];
}
}


2)================================

When trying to work with an array of std::string-pointers ...

func2( (std::string* []) { &std::string("ab"), &std::string("cd"),
&std::string("ef") } , 3 );
//
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// ~~ nextline

.... g++ reports:
"taking address of temporary" (reported 3 times)
"invalid use of non-lvalue array".

When are the 3 temporary addresses in danger of being "corrupted"? Is
it during the execution of func2, or is it only after func2, i.e.
at // ~~ nextline

How can the error be fixed?

void func2(std::string* arr[], int n)
{

// possible memory allocations etc...

while ((--n) >= 0) {
std::cout << *(arr[n]);
}
}



Thanks for advice!
-Albert
 
M

Martin York

Hello!

1) ===============================
When trying to define an array of std::string ...

func( (std::string []) { std::string("ab"), std::string("cd"),
std::string("ef") } , 3 );

Perl programmer are we? :)

Thats hard to read and I am not sure it would be valid syntax. It
looks like a comma expression to me, I don't think you can use the
array initializer like that (somebody with a copy of the standard will
give you the exact problem). Also the fact that you are using a C
style cast is an indication that something is not good with the code.

A simple solution would be:

std::string[] temp = {"ab","cd","ef"};
func(temp,3);



func2( (std::string* []) { &std::string("ab"), &std::string("cd"),
&std::string("ef") } , 3 );
//
... g++ reports:
"taking address of temporary" (reported 3 times)
"invalid use of non-lvalue array".


Temporary objects are constant and only last as long as the statement.
Thus taking there address is probably not a good idea that is why the
compiler is generating a "WARNING". Also again I don't think you are
actually creating an array. Using a cast like that forces the type to
be something without checking. The compiler is not adding any code to
do the conversion.

When are the 3 temporary addresses in danger of being "corrupted"? Is
it during the execution of func2, or is it only after func2, i.e.
at // ~~ nextline

The temporaries are valid until the end of the statement they are
created in (except in funny situations that don't arise here). So they
will be valid until after func2() returns.
 
A

Alf P. Steinbach

* Martin York -> (e-mail address removed):
func2( (std::string* []) { &std::string("ab"), &std::string("cd"),
&std::string("ef") } , 3 );
//
... g++ reports:
"taking address of temporary" (reported 3 times)
"invalid use of non-lvalue array".


Temporary objects are constant

Nope.

Temporaries behave like being constant wrt. to binding to references.

But they're not constant unless they have const type, and in particular,
you can call non-const non-static member functions on a temporary of
class type (unless the type is const), which includes assignment to a
temporary of class type, because operator= is then a member function...

struct S {};

void foo( S& ) {}

int main()
{
S() = S(); // OK.
// foo( S() ); // Ungood.
}

Cheers, & hth.,

- Alf
 
A

anon.asdf

Hello!

1) ===============================
When trying to define an array of std::string ...

func( (std::string []) { std::string("ab"), std::string("cd"),
std::string("ef") } , 3 );

void func(std::string arr[], int n)
{
while ((--n) >= 0) {
std::cout << arr[n];
}

}

Interestingly, the following works fine:

//===================================
#include <iostream>

void func3(char* arr[], int n);

int main(void)
{
func3((char* []){"ab", "cd", "ef"}, 3);
return 0;
}

void func3(char* arr[], int n)
{
while ((--n) >= 0) {
std::cout << arr[n];
}
std::cout << std::endl;
}
//===================================

Can it be similarly adapted for std::string, without naming an array
variable?

-Albert
 
A

Alf P. Steinbach

* (e-mail address removed):
Hello!

1) ===============================
When trying to define an array of std::string ...

func( (std::string []) { std::string("ab"), std::string("cd"),
std::string("ef") } , 3 );

void func(std::string arr[], int n)
{
while ((--n) >= 0) {
std::cout << arr[n];
}

}

Interestingly, the following works fine:

//===================================
#include <iostream>

void func3(char* arr[], int n);

int main(void)
{
func3((char* []){"ab", "cd", "ef"}, 3);
return 0;
}

void func3(char* arr[], int n)
{
while ((--n) >= 0) {
std::cout << arr[n];
}
std::cout << std::endl;
}
//===================================

<quote>
V:\> gnuc vc_project.cpp
vc_project.cpp: In function `int main()':
vc_project.cpp:7: error: ISO C++ forbids compound-literals

V:\> msvc vc_project.cpp
vc_project.cpp
vc_project.cpp(7) : error C2143: syntax error : missing ')' before '{'
vc_project.cpp(7) : error C2059: syntax error : ')'
vc_project.cpp(7) : error C2143: syntax error : missing ';' before '{'
vc_project.cpp(7) : error C2143: syntax error : missing ';' before '}'
vc_project.cpp(7) : error C2143: syntax error : missing ';' before ','
vc_project.cpp(7) : error C2059: syntax error : ')'

V:\>_
Can it be similarly adapted for std::string, without naming an array
variable?

No.

It seems the compiler+options you're using allows the above as an extension.

It might be that it's syntax that has been introduced in C99, but it's
not C++.


Cheers, & hth.,

- Alf
 
D

Dario Saccavino

Temporaries behave like being constant wrt. to binding to references.

But they're not constant unless they have const type, and in particular,
you can call non-const non-static member functions on a temporary of
class type (unless the type is const), which includes assignment to a
temporary of class type, because operator= is then a member function...

What is the reason for this behaviour?

It seems to me that it breaks the distinction between R-value and L-
value. The following two snippets:

X a, b, c;
a + b = c;

X f(); // extern function
void g()
{
X x;
f() += x;
}

both cause a compile error when X = int, but they become valid (at
least, with all the compilers and libraries that I could test) if I
use X = std::complex<int> or X = std::string. And they both look like
logical errors by the programmer.

Furthermore, as pointed out by some previous threads in this
newsgroup, this behaviour introduces a difference between an operator
declared as a class method and the same operator declared as a global
function; this difference may also lead to bugs that are hard to track
and hard to explain to novice programmers.

What do we gain from this feature?

Dario
 
A

Alf P. Steinbach

* Dario Saccavino:
What is the reason for this behaviour?

It seems to me that it breaks the distinction between R-value and L-
value. The following two snippets:

X a, b, c;
a + b = c;

X f(); // extern function
void g()
{
X x;
f() += x;
}

both cause a compile error when X = int, but they become valid (at
least, with all the compilers and libraries that I could test) if I
use X = std::complex<int> or X = std::string. And they both look like
logical errors by the programmer.

Heh heh. :) It's much worse. Consider

struct S { int v; };

S foo() { return S(); }

int main()
{
foo() = S(); // OK, can change the whole shebang.
foo().v = 0; // Nyet! Can not change part!
}

As it happens both g++ 3.4.4 and msvc 7.1 compile this fine (or rather,
erronously), but Comeau Online 4.3.9 reports for the last assignment
that "expression must be a modifiable lvalue".

Furthermore, as pointed out by some previous threads in this
newsgroup, this behaviour introduces a difference between an operator
declared as a class method and the same operator declared as a global
function;

Good observation. May relate to why operator= can only be defined as a
member function. Bjarne stated somewhere that it was to (my words) keep
some degree of sanity, something you could rely on, and I had difficulty
understanding what that meant, but possibly it could refer to the
discrimination between rvalues and lvalues that a freestanding operator=
would give. Although I still do not quite understand it. Possibly the
rvalue/lvalue distinction doesn't really make sense in C++.

This discussion could possibly benefit from being brought to comp.std.c++.

Except -- that group's temporarily down.

this difference may also lead to bugs that are hard to track
and hard to explain to novice programmers.

What do we gain from this feature?

One example that I remember being mentioned is, for a multi-dimensional
logical array, the ability to define an operator[] that returns a proxy
object that can be assigned to (the first level proxy object would then
itself also provide an operator[], the purpose being to not expose the
logical array's internal memory layout or general implementation).

However, in most real-world cases the proxy object would not need to be
modified by the assignment, so you could define

struct Proxy
{
Proxy const& operator=( SomeElementType const& ) const;
};

So I think perhaps a better example is the stringizer (or more generally
the idea of chaining calls, used e.g. in named arguments idiom),

struct Str
{
std::eek:stringstream stream;

template< typename T >
Str& operator<<( T const& v ) { stream << v; return *this; }

operator std::string() const { return stream.str(); }
};

void foo( std::string const& ) {}

int main()
{
foo( Str() << "Line " << 42 << "." );
}


Cheers,

- Alf
 
J

James Kanze

* Dario Saccavino:

I'd consider it mainly a side effect of a lot of other
decisions. Each one justified in isolation, but the final
results can be rather confusing.
Heh heh. :) It's much worse. Consider
struct S { int v; };
S foo() { return S(); }
int main()
{
foo() = S(); // OK, can change the whole shebang.
foo().v = 0; // Nyet! Can not change part!
}
As it happens both g++ 3.4.4 and msvc 7.1 compile this fine
(or rather, erronously), but Comeau Online 4.3.9 reports for
the last assignment that "expression must be a modifiable
lvalue".

Yep. The real problem here (or at least one way of viewing it)
is that in the first case, you're dealing with a member function
(S::eek:perator=()---the fact that the compiler writes it, and not
you, doesn't change things here), and not an assignment
operator, so the rules concerning calling a member function
apply. In the second, of course, it's the built-in operator =
which is being used.

The built-in operator = requires an lvalue. A member function
doesn't.
Good observation. May relate to why operator= can only be
defined as a member function. Bjarne stated somewhere that it
was to (my words) keep some degree of sanity, something you
could rely on, and I had difficulty understanding what that
meant, but possibly it could refer to the discrimination
between rvalues and lvalues that a freestanding operator=
would give. Although I still do not quite understand it.
Possibly the rvalue/lvalue distinction doesn't really make
sense in C++.

I suspect that his statement referred more to what might happen
if the declaration of a non member operator= was visible in some
cases, and not in others. Sometimes getting the compiler
generated default when you've declared one explicitly would also
be very, very confusing.

The problem remains that the concept of lvalue/rvalue, as
inherited from C, doesn't work very well with objects of class
type. There are a couple of patterns where being able to call
member functions on a temporary object is essential. The
standard wanted to support that. Binding a temporary to a
non-const reference had proven to be seriously error prone. The
standard wanted to forbid it. (Note that these two rules
together mean that a user defined operator++ can be used on a
temporary, if it is a member function, but not if it is a free
function.) And the standard also tries to maintain the C
distinction between lvalues and rvalues where it can. The
results are confusing to say the least.
This discussion could possibly benefit from being brought to
comp.std.c++.
Except -- that group's temporarily down.

Only temporarily, I hope. (It's been down for more than a month
now.)
One example that I remember being mentioned is, for a
multi-dimensional logical array, the ability to define an
operator[] that returns a proxy object that can be assigned to
(the first level proxy object would then itself also provide
an operator[], the purpose being to not expose the logical
array's internal memory layout or general implementation).
However, in most real-world cases the proxy object would not
need to be modified by the assignment, so you could define
struct Proxy
{
Proxy const& operator=( SomeElementType const& ) const;
};

That's what Scott Meyers suggests. It has the advantage that it
very much signals the object as a Proxy---the fact that
operator= is const should definitely signal something.
So I think perhaps a better example is the stringizer (or more generally
the idea of chaining calls, used e.g. in named arguments idiom),
struct Str
{
std::eek:stringstream stream;
template< typename T >
Str& operator<<( T const& v ) { stream << v; return *this; }
operator std::string() const { return stream.str(); }
};
void foo( std::string const& ) {}
int main()
{
foo( Str() << "Line " << 42 << "." );
}

I think that's more or less the real argument. The example I
remember was something like:

new Window( WindowParameters().background( Color::red ) ) ;

A window can typically have something like a hundred different
parameters, most of which will use the default value most of the
time. So you wrap them in a WindowParameters class, whose
constructor sets them all to the default value, and then you
call explicit functions (which return a WindowParameters&) to
change the ones you want changed.

There are possible alternative rules, but they all fall down
somewhere as well.
 

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

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,835
Latest member
KetoRushACVBuy

Latest Threads

Top