What is the output of this program? and why?

K

kalamantina

#include "stdafx.h"
#include <stdio.h>
#define output( x ) printf( #x "\r\n" );fflush( stdout )
class CMyBase
{
public:
CMyBase()
{
output( CMyBase() );
f(*this);
}
CMyBase( CMyBase& b )
{
output( CMyBase( copy ) );
}
CMyBase( int i ) { output( CMyBase( int ) ); }
virtual CMyBase f(CMyBase& b) { output( CMyBase::f() ); return b; }
};
class CDerived : public CMyBase
{
public:
CDerived()
{
output( CDerived() );
}
CDerived( CMyBase other )
{
output( "CDerived()" );
}
virtual CMyBase f(CMyBase& b) { output( first ); return b; }
virtual CMyBase f(CMyBase b) const { output( second ); return b; }
~CDerived()
{
output(~CDerived);
}
};
int main(int argc, char* argv[])
{
CDerived a;
CMyBase* p = &a;
CDerived b = a;
p->f(b);
b = a;
a.f( 5 );
a.f( b );
 
V

Victor Bazarov

#include "stdafx.h"
[...]

The program is incomplete, it contains at least one non-standard
construct and therefore it won't even compile. Also, read FAQ 5.2.

V
 
K

kalamantina

Which construct is non standard?
Plus this are the libraries included:

#include "stdafx.h"
#include <stdio.h>
#define output( x ) printf( #x "\r\n" );fflush( stdout )
 
D

Daniel T.

There shouldn't be any output at all. The program shouldn't compile.
#include "stdafx.h"
#include <stdio.h>
#define output( x ) printf( #x "\r\n" );fflush( stdout )
class CMyBase
{
public:
CMyBase()
{
output( CMyBase() );
f(*this);
}
CMyBase( CMyBase& b )
{
output( CMyBase( copy ) );
}
CMyBase( int i ) { output( CMyBase( int ) ); }
virtual CMyBase f(CMyBase& b) { output( CMyBase::f() ); return b; }
};
class CDerived : public CMyBase
{
public:
CDerived()
{
output( CDerived() );
}
CDerived( CMyBase other )
{
output( "CDerived()" );
}
virtual CMyBase f(CMyBase& b) { output( first ); return b; }
virtual CMyBase f(CMyBase b) const { output( second ); return b; }
~CDerived()
{
output(~CDerived);
}
};
int main(int argc, char* argv[])
{
CDerived a;
CMyBase* p = &a;
CDerived b = a;
p->f(b);
b = a;
a.f( 5 );

The above code implicitly creates a CMyBase using the "CMyBase(int)"
c_tor then tries to pass it to CDerived::f(CMyBase&). It can't do that
though because the CMyBase created is a temporary and so can't be passed
in.
a.f( b );

Also, main isn't complete.
 
J

Jim Langston

Subject of message: "What is the output of this program? and why?"

Please make sure you also put the question in the message body itself.

If you have the code, why are you asking what the output is? Didn't you try
it?

(This is not technically top posting, by the way, since I'm replying to his
subject)
 
M

Mike Wahler

Daniel T. said:
How could code that doesn't compile output anything at all?

An implementation is not prohibited from producing
an executable from source that contains code
which requires diagnostics. Of course the
behavior of such a program would be undefined,
so output, if any, could be anything at all.

-Mike
 
J

jesper

#include "stdafx.h"
#include <stdio.h>
#define output( x ) printf( #x "\r\n" );fflush( stdout )

f() outputs x as a char * constant appended newline on stdout
class CMyBase
{
public:
CMyBase()
{
output( CMyBase() );
f(*this);
}
standard constructor outputs "CMyBase()\r\n"
and calls overloaded function with CMyBase& argument
CMyBase( CMyBase& b )
{
output( CMyBase( copy ) );
}
CopyConstructor does nothing except outputs "CMyBase( copy )\r\n"
CMyBase( int i ) { output( CMyBase( int ) ); }
Constructor(int) does nothing except outputs "CMyBase( int )\r\n"
virtual CMyBase f(CMyBase& b) { output( CMyBase::f() ); return b; }
Overloaded f() does returns calls copyconstuctor. outputs
"CMyBase::f()\r\nCMyBase( copy )\r\n"
};
class CDerived : public CMyBase
{
public:
CDerived()
{
output( CDerived() ); outputs " CDerived()\r\n"
}
CDerived( CMyBase other )
{
output( "CDerived()" ); outputs "CDerived()\r\n"
}
virtual CMyBase f(CMyBase& b) { output( first ); return b; }
outputs "first\r\nCMyBase( copy )\r\n"
virtual CMyBase f(CMyBase b) const { output( second ); return b; }
outputs "CMyBase( copy )\r\nsecond\r\nCMyBase( copy )\r\n"
~CDerived()
{
output(~CDerived); outputs "~CDerived\r\n"
}
};
int main(int argc, char* argv[])
{
CDerived a;
Construct a cderived.
Calls CBase(),CDerived()
CMyBase* p = &a; no calls
CDerived b = a;
CBase(),CBase(),CDerived( CMyBase other ) *not sure here*
calls f(CMyBase& b)
CDerived( CMyBase other ) *not sure here*
a.f( 5 ); calls f(CMyBase(int) b) const
a.f( b );
calls f(CMyBase& b)


My guess is Output:
CBase()
CDerived()
CBase()
CBase()
CDerived()
first
CMyBase( int )
CMyBase( copy )
CDerived( CMyBase other )
CMyBase( copy )
second
CMyBase( copy )
first
CMyBase( copy )
 
J

jesper

I read the thread after I tried to solve it I confess.
But I must disagree with this not being supposed to compile (except no
closing bracket for main which is petty to point out IMHO).

Quoted:

"The above code implicitly creates a CMyBase using the "CMyBase(int)"
c_tor then tries to pass it to CDerived::f(CMyBase&). It can't do that
though because the CMyBase created is a temporary and so can't be
passed
in.
a.f( b ); "
Assuming the poster means a.f(5); : (just for clearification not being
petty here)

The implicit call to CMyBase(int) creates a temporary instance of
CMyBase and passes that to a function. This is perfectly fine, and
actually
central to the entire idea of implicit type conversions. Every C++
program does this all the time.
Well of course you can build a program that doesn't but thats beside
the point.
What would be illegal is to try to return that implicitly created
object as a reference.
because then the object would be out of scope.

Basically, Passing temporary objects to functions is fine.
/Jesper
 
A

Alf P. Steinbach

* (e-mail address removed):
> [forgot to include the question]

One must presume you have a compiler at hand (that this is not HOMEWORK
by some less than competent lecturer), and so that the question is meant
to be what the output should be according to the standard.

#include "stdafx.h"

No such thing in standard C++.

We don't know what e.g. macros that file drags in, hence output is in
principle unknowable.

However, let's disregard that.

#include <stdio.h>
#define output( x ) printf( #x "\r\n" );fflush( stdout )

As a novice, use typesafe C++ iostreams instead, and DO NOT use macros.

class CMyBase
{
public:
CMyBase()
{
output( CMyBase() );
f(*this);
}
Indentation!


CMyBase( CMyBase& b )
{
output( CMyBase( copy ) );
}
CMyBase( int i ) { output( CMyBase( int ) ); }
virtual CMyBase f(CMyBase& b) { output( CMyBase::f() ); return b; }

Using copy constructor with side effects in a context where calls to
that copy constructor can be elided; hence, output is unspecified even
if the rest of the code is OK technically (haven't checked, no need).
 
J

jesper

Alf said:
Using copy constructor with side effects in a context where calls to
that copy constructor can be elided; hence, output is unspecified even
if the rest of the code is OK technically (haven't checked, no need).
I do not see the problem here.
Output from this function is always the same.

We recieve a reference to an object. Then afte we are done we return a
implicitly created copy of that (updated) object.

scenario (peudocode):
vector<string> names;
vector<string> input(vector<string> &refnames)
{
//code to read string from keyboard
return refnames;
}
void prune(vector<string> &names,string condition)
{
// remove strings according to conditiion
}
int main()
{
vector<string> pruned=input(names);
prune(pruned,"sounds like 'Garbage'");
// Do some work
return 0;
}
//end pseudocode
What in this is unpredictable?
/Jesper
Ps. Is there somewhere to discuss macros?
I do not agree you should not use them.
Careful planing might make them mostly unnecessary
but they can be a great tool.
DS.
 
A

Alf P. Steinbach

* (e-mail address removed):
>
I do not see the problem here.
Output from this function is always the same.

No, it's unspecified whether the copy constructor is called or not.

We recieve a reference to an object. Then afte we are done we return a
implicitly created copy of that (updated) object.

scenario (peudocode):
vector<string> names;
vector<string> input(vector<string> &refnames)
{
//code to read string from keyboard
return refnames;
}
void prune(vector<string> &names,string condition)
{
// remove strings according to conditiion
}
int main()
{
vector<string> pruned=input(names);
prune(pruned,"sounds like 'Garbage'");
// Do some work
return 0;
}
//end pseudocode
What in this is unpredictable?

Whether the vector<string> copy constructor is called or not for a call
to 'input', and if it's called, how many times, is unpredictable.

Ps. Is there somewhere to discuss macros?

Start a new thread in this group.

I do not agree you should not use [generally] them.

Some novices may agree with you. ;-)
 
J

jesper

Alf said:
* (e-mail address removed):

No, it's unspecified whether the copy constructor is called or not.
Why? In which instant is that undefined? I would assume return b;
always calls the copy constructor.
And when calling the function that is not just undefined but also
irrelevant
to the function.
The function does not care wheter the reference it recieves is implicit
or explicit.
The user of the class must decide how to use it. Or am I wrong here?
If I am, can you teach me better?
/Jesper
 
A

Alf P. Steinbach

* (e-mail address removed):
>
I would assume return b; always calls the copy constructor.

Nope. But there's a difference between practice and utterly formal
theory. In theory that call can only be removed (regardless of
side-effects) when b is a local variable (this is known as NRVO) or a
non-bound temporary (RVO). In practice the fact that you can't rely on
side-effects in copy constructors -- that they may not be called, due
to NRVO and RVO, or may called arbitrarily many times for a single
initialization -- means that compilers can optimize such things very
aggressively, and few if anybody will complain about it.

And when calling the function that is not just undefined but also
irrelevant to the function.
?

The function does not care wheter the reference it recieves is implicit
or explicit.
?


The user of the class must decide how to use it. Or am I wrong here?
If I am, can you teach me better?

The compiler is free to optimize away copy constructor calls in many
contexts (para 12.8/15 of the standard, updated in C++2003), regardless
of side-effects in the copy constructors and destructors involved. Copy
constructors and destructors are special that way. They're the only
functions (at least as far as I know) that the compiler is free to
_assume_ have no side-effects, in certain situations.
 
J

jesper

Alf said:
The compiler is free to optimize away copy constructor calls in many
contexts (para 12.8/15 of the standard, updated in C++2003), regardless
of side-effects in the copy constructors and destructors involved. Copy
constructors and destructors are special that way. They're the only
functions (at least as far as I know) that the compiler is free to
_assume_ have no side-effects, in certain situations.

:) I did not know this. I certainly hope they are the only ones.
Does this mean letting constructors and destructors manage a static
collection of
pointers to created objects is no longer a good idea? sounds dangerous
to me.
/Jesper
 
D

Daniel T.

I read the thread after I tried to solve it I confess.
But I must disagree with this not being supposed to compile (except no
closing bracket for main which is petty to point out IMHO).

Quoted:

"The above code implicitly creates a CMyBase using the "CMyBase(int)"
c_tor then tries to pass it to CDerived::f(CMyBase&). It can't do that
though because the CMyBase created is a temporary and so can't be
passed
in.
Assuming the poster means a.f(5); : (just for clearification not being
petty here)

The implicit call to CMyBase(int) creates a temporary instance of
CMyBase and passes that to a function. This is perfectly fine, and
actually central to the entire idea of implicit type conversions.

The problem in this context however is that there is no function that
can legally accept the temporary instance.
Every C++ program does this all the time.
Well of course you can build a program that doesn't but thats beside
the point.
What would be illegal is to try to return that implicitly created
object as a reference.
because then the object would be out of scope.

Basically, Passing temporary objects to functions is fine.

Not in the context you created. Here is the error from comeau:

error: "CMyBase::CMyBase(CMyBase &)", required for copy that was
eliminated, is not callable because reference parameter cannot be bound
to rvalue

And from gcc:

error: no matching function for call to `CMyBase::CMyBase(CMyBase)'
candidates are: CMyBase::CMyBase(int)
CMyBase::CMyBase(CMyBase&)
 
J

jesper

Daniel said:
[snip]
I read the thread after I tried to solve it I confess.

Not in the context you created. Here is the error from comeau:

error: "CMyBase::CMyBase(CMyBase &)", required for copy that was
eliminated, is not callable because reference parameter cannot be bound
to rvalue

And from gcc:

error: no matching function for call to `CMyBase::CMyBase(CMyBase)'
candidates are: CMyBase::CMyBase(int)
CMyBase::CMyBase(CMyBase&)
It is a silly piece of code I must agree. Designed to be difficult to
dechipher.
And I bow to all you guys obviously superior knowledge. I'm humbled.
:)

What is the borland compiler doing wrong here then? (since I compiled
it and ran it just fine)
Should I begin to doubt all programs I have made for it?
(I know about borlands herasy with the standard on acount of the vcl.
And I really am two minds about the additions they have made. On the
one hand its certainly more readable, but on the other its less
portable. But have they made some dangerous stuff to core
functionality?)

/Jesper
 

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,772
Messages
2,569,593
Members
45,111
Latest member
KetoBurn
Top