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

Visual Studio C++ .NET 2003 Compiler optimization (Bug ?)

8 views
Skip to first unread message

Girish P

unread,
Jan 9, 2006, 2:04:35 AM1/9/06
to
using namespace std;
class foobar {
public:
foobar() { cout << "foobar::foobar()\n"; }
~foobar() { cout << "foobar::~foobar()\n"; }
foobar(int nval ):_ival(nval) { cout << "foobar::foobar(int)\n"; }
foobar( const foobar &rhs ) { cout << "foobar::foobar( const foobar
& )\n"; }
operator int(){ cout<<"foobar::operator int()"<<endl; return _ival; }
private:
int _ival;
};


foobar f( int val )
{
return foobar();
}

void main()
{
foobar foo = f(1024);
}


In the above program,

I see 3 different behaviors:
1. Run the program as it is, only one foobar object is created.
2. Remove the const qualifier from the copy constructor, there are 3 foobar
objects created. Strange thing is that "operator int()" method is used while
copying data to temporary objects. Why?
3. commenting the "operator int()" method will result back in only one
foobar object creation.

Could anyone kindly explain the behavior for me?


Ulrich Eckhardt

unread,
Jan 9, 2006, 3:04:46 AM1/9/06
to
Girish P wrote:
> using namespace std;
> class foobar {
> public:
> foobar() { cout << "foobar::foobar()\n"; }
> ~foobar() { cout << "foobar::~foobar()\n"; }
> foobar(int nval ):_ival(nval) { cout << "foobar::foobar(int)\n"; }
> foobar( const foobar &rhs ) { cout << "foobar::foobar( const foobar
> & )\n"; }
> operator int(){ cout<<"foobar::operator int()"<<endl; return _ival; }
> private:
> int _ival;
> };

Search for the so-called "Law of Three", you're missing a part here to be
complete. Other than that, the ctor taking an int should be marked as
explicit. Well, at least these things apply to production code, that is...

> foobar f( int val )
> {
> return foobar();
> }
>
> void main()
> {
> foobar foo = f(1024);
> }
>
>
> In the above program,
>
> I see 3 different behaviors:
> 1. Run the program as it is, only one foobar object is created.

This is a valid optimisation not only done by MSC but other compilers, too.

> 2. Remove the const qualifier from the copy constructor, there are 3
> foobar objects created. Strange thing is that "operator int()" method is
> used while copying data to temporary objects. Why?

You can't bind a temporary to a non-const reference. The returnvalue from a
function is a temporary which doesn't work as input for the ctor in main(),
so that ctor can't be used. Then, of course, its use can't be optimised
away.

> 3. commenting the "operator int()" method will result back in only one
> foobar object creation.

Interesting. I can't tell you which way it is taking in that case. I'd ask
in comp.lang.c++.moderated and/or try with a different compiler.

Uli

--
http://got.to/quote
Read this as I won't help you unless you make your posts readable or provide
a fascinating problem.

Igor Tandetnik

unread,
Jan 9, 2006, 8:16:18 AM1/9/06
to
"Ulrich Eckhardt" <eckh...@satorlaser.com> wrote in message
news:ith993-...@satorlaser.homedns.org

>> 3. commenting the "operator int()" method will result back in only
>> one foobar object creation.
>
> Interesting. I can't tell you which way it is taking in that case.
> I'd ask in comp.lang.c++.moderated and/or try with a different
> compiler.

VC compiler by default does allow binding temporary to a non-const
reference. I suspect that's what happens in case #3. This behavior can
be turned off by compiling in strict ANSI mode (/Za).

This conversion, when enabled, is ranked lowest in overload resolution,
that's why #2 chooses to convert to int and use a constructor from int.
--
With best wishes,
Igor Tandetnik

With sufficient thrust, pigs fly just fine. However, this is not
necessarily a good idea. It is hard to be sure where they are going to
land, and it could be dangerous sitting under them as they fly
overhead. -- RFC 1925


Tom Widmer [VC++ MVP]

unread,
Jan 9, 2006, 8:15:48 AM1/9/06
to
Ulrich Eckhardt wrote:
> Girish P wrote:

>>2. Remove the const qualifier from the copy constructor, there are 3
>>foobar objects created. Strange thing is that "operator int()" method is
>>used while copying data to temporary objects. Why?
>
>
> You can't bind a temporary to a non-const reference. The returnvalue from a
> function is a temporary which doesn't work as input for the ctor in main(),
> so that ctor can't be used. Then, of course, its use can't be optimised
> away.
>
>
>>3. commenting the "operator int()" method will result back in only one
>>foobar object creation.
>
>
> Interesting. I can't tell you which way it is taking in that case. I'd ask
> in comp.lang.c++.moderated and/or try with a different compiler.

MSVC has an "extension" where it allows the binding of a temporary to a
non-const reference, and that binding seems to be given the lowest value
for the purposes of overloading (thus, it is designed to only make code
compile if it wouldn't otherwise compile, e.g. by calling operator int()
in the OPs example). You can disable this with /Za, and then an error is
generated as expected.

Tom

Doug Harrison [MVP]

unread,
Jan 9, 2006, 11:48:24 AM1/9/06
to
On Mon, 9 Jan 2006 12:34:35 +0530, "Girish P" <Gir...@yahoo.co.in> wrote:

>using namespace std;
>class foobar {
>public:
> foobar() { cout << "foobar::foobar()\n"; }
> ~foobar() { cout << "foobar::~foobar()\n"; }
> foobar(int nval ):_ival(nval) { cout << "foobar::foobar(int)\n"; }
> foobar( const foobar &rhs ) { cout << "foobar::foobar( const foobar
>& )\n"; }
> operator int(){ cout<<"foobar::operator int()"<<endl; return _ival; }
>private:
> int _ival;
>};
>
>
>foobar f( int val )
>{
> return foobar();
>}
>
>void main()
>{
> foobar foo = f(1024);
>}
>
>
>In the above program,
>
>I see 3 different behaviors:
>1. Run the program as it is, only one foobar object is created.

That indicates a high degree of optimization.

>2. Remove the const qualifier from the copy constructor, there are 3 foobar
>objects created. Strange thing is that "operator int()" method is used while
>copying data to temporary objects. Why?

The C++ Standard forbids binding a temporary to a non-const reference.
Therefore, f()'s return value cannot bind to the non-const copy ctor,
neither inside f() nor outside f() in the initialization of foo, and the
non-const copy ctor doesn't participate in overload resolution. This leaves
the ctor that takes an int, and since member functions can be called on
temporaries, the conversion function "operator int" makes it possible for
this ctor to work. (However, everything changes if the source type for all
this copying isn't foobar or a type derived from foobar. Then what
nominally is "copy-initialization" really is "copy-initialization" and
doesn't morph into "direct-initialization", and the rule concerning more
than one user-defined conversion comes into play.)

>3. commenting the "operator int()" method will result back in only one
>foobar object creation.

That's a bug. The program should not compile. VC gets all this complicated
mess about half right and allows binding temporaries to non-const
references most of the time.

--
Doug Harrison
Visual C++ MVP

0 new messages