expected behaviour of << operator

C

Carlo Capelli

Hi all.

Some time ago, upgrading MSVC, i had to debug a little problem, rising from
the change of behaviour of the following code:

#include <fstream>
void main()
{
std::eek:fstream("dummy") << "hello" << std::endl;
}

Using MSVC6, this resulted in a file dummy containing 'hello', after the
upgrade to VisualStudio2005 the file contains the numeric
address (like a fprintf(dummy, "%p", "hello\n"), or std::eek:fstream("dummy")
<< (void*)"hello").

Also gc (i don't know the version) that at the time come with Dev-C++ agreed
with the former outcome.

In my POV, this was a bug of the new compiler/enviroment (i.e. some change
of scope resolution ot include...), so I queried over MS listserv,
obtaining a querelle (of rather technical level) among (i presume) the
compiler' implementors. The outcome was that the compiler should reject the
code as invalid.

What do you think about?

Bye Carlo
 
A

Alf P. Steinbach

* Carlo Capelli:
Hi all.

Some time ago, upgrading MSVC, i had to debug a little problem, rising from
the change of behaviour of the following code:

#include <fstream>
void main()
{
std::eek:fstream("dummy") << "hello" << std::endl;
}

Using MSVC6, this resulted in a file dummy containing 'hello', after the
upgrade to VisualStudio2005 the file contains the numeric
address (like a fprintf(dummy, "%p", "hello\n"), or std::eek:fstream("dummy")
<< (void*)"hello").

Also gc (i don't know the version) that at the time come with Dev-C++ agreed
with the former outcome.

In my POV, this was a bug of the new compiler/enviroment (i.e. some change
of scope resolution ot include...), so I queried over MS listserv,
obtaining a querelle (of rather technical level) among (i presume) the
compiler' implementors. The outcome was that the compiler should reject the
code as invalid.

What do you think about?

It's currently invalid.

If you care to search you will find this discussed recently in this
group, as well as many threads earlier, but mostly using stringstream.


Cheers, & hth.,

- Alf
 
K

Kira Yamato

Hi all.

Some time ago, upgrading MSVC, i had to debug a little problem, rising from
the change of behaviour of the following code:

#include <fstream>
void main()
{
std::eek:fstream("dummy") << "hello" << std::endl;
}

Using MSVC6, this resulted in a file dummy containing 'hello', after the
upgrade to VisualStudio2005 the file contains the numeric
address (like a fprintf(dummy, "%p", "hello\n"), or std::eek:fstream("dummy")
<< (void*)"hello").

Also gc (i don't know the version) that at the time come with Dev-C++ agreed
with the former outcome.

In my POV, this was a bug of the new compiler/enviroment (i.e. some change
of scope resolution ot include...), so I queried over MS listserv,
obtaining a querelle (of rather technical level) among (i presume) the
compiler' implementors. The outcome was that the compiler should reject the
code as invalid.

What do you think about?

The expression
std::eek:fstream("dummy")
is a temporary object. As such, it cannot be bind to a non-const
reference, which the global function
operator<<(ostream &, const string &)
expects. So, the compiler cannot make this choice in your code.

Instead, the compiler finds a method in the class ostream with signature
operator<<(const void *)
which can fit in your code after an implicit pointer conversion
const char * --> const void *.

This is probably why you're seeing that behavior in VS2005.

Since I don't think the standard says you cannot invoke a method on a
temporary object, I don't know why you think the compiler should reject
the code as invalid.
 
C

Carlo Capelli

Kira Yamato said:
The expression
std::eek:fstream("dummy")
is a temporary object. As such, it cannot be bind to a non-const
reference, which the global function
operator<<(ostream &, const string &)
expects. So, the compiler cannot make this choice in your code.

Instead, the compiler finds a method in the class ostream with signature
operator<<(const void *)
which can fit in your code after an implicit pointer conversion
const char * --> const void *.

This is probably why you're seeing that behavior in VS2005.

Since I don't think the standard says you cannot invoke a method on a
temporary object, I don't know why you think the compiler should reject
the code as invalid.
Truly an exaustive response!
Many thanks (to Alf also...)
Carlo
 
J

Johan Hoogendoorn

he expression
std::eek:fstream("dummy")
is a temporary object. As such, it cannot be bind to a non-const
reference, which the global function
operator<<(ostream &, const string &)
expects. So, the compiler cannot make this choice in your code.

A follow-up question on this;

Personally my first guess that the temporary object remains in scope, until
the closing bracket '}' takes place, but then I wrote out the operator<<
calls...

The first operator << translates into "std::eek:fstream& operator
<<(std::eek:fstream&, std::string)".
To me it would indicate that the constructor of the temporary object takes
place in the parameter list of this FIRST operator<< call. To me sounded as
if the object's scope is limited to that of the method it's created in.

Since the return value of this call is then used in the second call (the
one featuring std::endl), does this mean that the first operator<< returns
a reference to a locally-defined object?

Sounds like this (returning a reference to a locally-defined object)
results in undefined behaviour. Is this assumption correct?

Kind regards,
Johan
 
A

Alf P. Steinbach

* Alf P. Steinbach:
* Carlo Capelli:

It's currently invalid.

Too fast, very very sorry.

Now I've got some coffee in my system.

It should find and use the member function basic_ostream::eek:perator<<(
void const* ).

If you care to search you will find this discussed recently in this
group, as well as many threads earlier, but mostly using stringstream.

Cheers,

- Alf
 
A

Alf P. Steinbach

* Carlo Capelli:
Truly an exaustive response!
Many thanks (to Alf also...)

Sorry, that's incorrect. <g> I mean, I wrote on non-caffeinated blood.
I've posted a correction.

Cheers,

- Alf
 
K

Kira Yamato

A follow-up question on this;

Personally my first guess that the temporary object remains in scope, until
the closing bracket '}' takes place, but then I wrote out the operator<<
calls...

Actually, the scope of a temporary object is on the statement level.
So, in this case it would be the semicolon instead of the closing
braces.
The first operator << translates into "std::eek:fstream& operator
<<(std::eek:fstream&, std::string)".

Actually, the first operator << translates into

std::eek:fstream::eek:perator(void * const).
To me it would indicate that the constructor of the temporary object takes
place in the parameter list of this FIRST operator<< call. To me sounded as
if the object's scope is limited to that of the method it's created in.

As I said before, it extends to the semicolon --- the statement ending
delimiter.
Since the return value of this call is then used in the second call (the
one featuring std::endl), does this mean that the first operator<< returns
a reference to a locally-defined object?
Yes.


Sounds like this (returning a reference to a locally-defined object)
results in undefined behaviour. Is this assumption correct?

I don't recall that the standard says invoking a method of a temporary
object is undefined behavior.
 
K

Kai-Uwe Bux

Johan Hoogendoorn said:
A follow-up question on this;

Personally my first guess that the temporary object remains in scope,
until the closing bracket '}' takes place, but then I wrote out the
operator<< calls...

The first operator << translates into "std::eek:fstream& operator
<<(std::eek:fstream&, std::string)".

No. It translates as

std::eek:fstream("dummy").operator<<( "hello" )

and returns a reference to the temporary ofstream object.
To me it would indicate that the constructor of the temporary object takes
place in the parameter list of this FIRST operator<< call. To me sounded
as if the object's scope is limited to that of the method it's created in.

No (see above) and no: the example below is contrived because it is somewhat
difficult to set up a situation where your question applies (temporaries do
not bind to non-const references without trickery); anyhow, consider:

class some_type {
public:

some_type & me ( void ) {
return ( *this );
}

};

some_type value;

swap( some_type().me(), value ); // (*)

The line (*) has well-defined behavior. The temporary that is created dies
only after the evaluation of the full expression that triggered its
creation.
Since the return value of this call is then used in the second call (the
one featuring std::endl), does this mean that the first operator<< returns
a reference to a locally-defined object?

Sounds like this (returning a reference to a locally-defined object)
results in undefined behaviour. Is this assumption correct?

No.


Best

Kai-Uwe Bux
 

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,767
Messages
2,569,572
Members
45,045
Latest member
DRCM

Latest Threads

Top