473,405 Members | 2,310 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,405 software developers and data experts.

Another base/derived problem with gcc, but not with MSVC

When i compile the program listed below with gcc version 3.3.1 (MinGW on
Windows XP) I get the following result:

Calling 'func(d)':
'base' copy constructor

Calling 'func(*d_handle)':
'base' copy constructor

Calling 'func(d_handle)':
'derived' copy constructor <-- Why?
'base' copy constructor

The problem is the call to the 'derived' copy constructor, which I don't
want and hadn't expected, and which Microsoft Visual C++ 6.0 doesn't
generate.

Is it the gcc or the MSVC compiler that is broken? I would naively have
assumed that MSVC is right and gcc is wrong in this case, but perhaps
there is something in the standard that prescribes the gcc behavior for
some reason?

My intention was that there shouldn't be any temporary 'derived' objects
created at all, since both the implicit conversion operator from
'derived_handle' to 'derived' and 'derived's operator* return references
to an existing 'derived' object.

After having recived some expert answers on this list on a somewhat
related question, I am nowadays aware of the rule that says that a
temporary object can't be tied to a non-const reference function
parameter, but that shouldn't have anything to do with this problem,
should it?

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

//----------------------------------------------------------------------------
class base
{
public:
base() {}
base(const base&) {std::cout << " 'base' copy constructor" <<
std::endl;}
};
//----------------------------------------------------------------------------
class derived : public base
{
public:
derived() {}
derived(const derived&) {std::cout << " 'derived' copy constructor"
<< std::endl;}
};
//----------------------------------------------------------------------------
class derived_handle
{
derived* tptr;

public:
derived_handle() {};
derived_handle(derived* inptr) : tptr(inptr) {}

derived& operator*() const {return *tptr;}
derived* operator->() const {return tptr;}

operator derived&() const {return **this;} // Implicit conversion
to 'derived'
};
//----------------------------------------------------------------------------
void func(base b) {} // Takes the parameter by value
//================================================== ==========================
int main (int argc, char* argv[])
{
derived d;
derived_handle d_handle(new derived());

std::cout << "\nCalling 'func(d)':" << std::endl;
func(d);

std::cout << "\nCalling 'func(*d_handle)':" << std::endl;
func(*d_handle);

std::cout << "\nCalling 'func(d_handle)':" << std::endl;
func(d_handle); // Calls 'derived' copy constructor with gcc (only)

return 0;
}

Jul 22 '05 #1
7 1607

"Christian Engström" <ch****************@glindra.org> wrote in message
news:yz***************@news.ecrc.de...
When i compile the program listed below with gcc version 3.3.1 (MinGW on
Windows XP) I get the following result:

Calling 'func(d)':
'base' copy constructor

Calling 'func(*d_handle)':
'base' copy constructor

Calling 'func(d_handle)':
'derived' copy constructor <-- Why?
'base' copy constructor

The problem is the call to the 'derived' copy constructor, which I don't
want and hadn't expected, and which Microsoft Visual C++ 6.0 doesn't
generate.

Is it the gcc or the MSVC compiler that is broken? I would naively have
assumed that MSVC is right and gcc is wrong in this case, but perhaps
there is something in the standard that prescribes the gcc behavior for
some reason?

My intention was that there shouldn't be any temporary 'derived' objects
created at all, since both the implicit conversion operator from
'derived_handle' to 'derived' and 'derived's operator* return references
to an existing 'derived' object.

After having recived some expert answers on this list on a somewhat
related question, I am nowadays aware of the rule that says that a
temporary object can't be tied to a non-const reference function
parameter, but that shouldn't have anything to do with this problem,
should it?

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

//--------------------------------------------------------------------------
-- class base
{
public:
base() {}
base(const base&) {std::cout << " 'base' copy constructor" <<
std::endl;}
};
//--------------------------------------------------------------------------
-- class derived : public base
{
public:
derived() {}
derived(const derived&) {std::cout << " 'derived' copy constructor"
<< std::endl;}
};
//--------------------------------------------------------------------------
-- class derived_handle
{
derived* tptr;

public:
derived_handle() {};
derived_handle(derived* inptr) : tptr(inptr) {}

derived& operator*() const {return *tptr;}
derived* operator->() const {return tptr;}

operator derived&() const {return **this;} // Implicit conversion
to 'derived'
};
//--------------------------------------------------------------------------
-- void func(base b) {} // Takes the parameter by value
//================================================== ========================
== int main (int argc, char* argv[])
{
derived d;
derived_handle d_handle(new derived());

std::cout << "\nCalling 'func(d)':" << std::endl;
func(d);

std::cout << "\nCalling 'func(*d_handle)':" << std::endl;
func(*d_handle);

std::cout << "\nCalling 'func(d_handle)':" << std::endl;
func(d_handle); // Calls 'derived' copy constructor with gcc (only)

return 0;
}


I can't claim any expertise, I'm only answering because no-one else has.

I think you are getting into obscure areas of C++ which you would be well
advised to stay away from. Even if you could find out what the official
position was there is no guarantee that compilers would implement it
correctly.

FWIW I believe that the position is this, compilers are allow to silently
add or remove calls to copy constructors in certain circumstances (e.g.
creation of temporaries, return value optimisation) EVEN IF those copy
constructors have side effects. Essentially you must write your copy
constructors in such a way that you don't mind if they are called on the odd
occasion when you weren't expecting it (or not called when you were
expecting it).

For a definitive answer to your particular case I'd buy a copy of the C++
standard or perhaps you could try your question again in
comp.lang.c++.moderated where the high powered folks hang out.

john
Jul 22 '05 #2
John Harrison wrote:

I can't claim any expertise, I'm only answering because no-one else has.

I think you are getting into obscure areas of C++ which you would be well
advised to stay away from. Even if you could find out what the official
position was there is no guarantee that compilers would implement it
correctly.
Yes, I seem to have run into a quite unlikely series of obscure compiler
problems with this one.

I *was* intending to design something that was slightly outside the
well-trodden main road, but it appears that I have walked right up to
the end of the world and that I'm beginning to fall over the edge. :-)

FWIW I believe that the position is this, compilers are allow to silently
add or remove calls to copy constructors in certain circumstances (e.g.
creation of temporaries, return value optimisation) EVEN IF those copy
constructors have side effects. Essentially you must write your copy
constructors in such a way that you don't mind if they are called on the odd
occasion when you weren't expecting it (or not called when you were
expecting it).
Hm. I'm not arguing with what you say, but that would essentially mean
that the behavior of any C++ program that contains a non-trivial copy
constructor is undefined. And since most real world C++ programs do,...

For a definitive answer to your particular case I'd buy a copy of the C++
standard or perhaps you could try your question again in
comp.lang.c++.moderated where the high powered folks hang out.

john


Right, I'll try c.l.c++.moderated.

Thanks a lot for the answer, anyway!

/Christian

Jul 22 '05 #3
>
FWIW I believe that the position is this, compilers are allow to silently add or remove calls to copy constructors in certain circumstances (e.g.
creation of temporaries, return value optimisation) EVEN IF those copy
constructors have side effects. Essentially you must write your copy
constructors in such a way that you don't mind if they are called on the odd occasion when you weren't expecting it (or not called when you were
expecting it).


Hm. I'm not arguing with what you say, but that would essentially mean
that the behavior of any C++ program that contains a non-trivial copy
constructor is undefined. And since most real world C++ programs do,...


If the non-trivial copy constructor has a side effect then yes. But most
copy constructors (trivial or not) do nothing other than copy objects.

john
Jul 22 '05 #4


Christian Engström wrote:
John Harrison wrote:

I can't claim any expertise, I'm only answering because no-one else has.

I think you are getting into obscure areas of C++ which you would be well
advised to stay away from. Even if you could find out what the official
position was there is no guarantee that compilers would implement it
correctly.

Yes, I seem to have run into a quite unlikely series of obscure compiler
problems with this one.


It looks like a gcc bug. The compiler is treating the returned derived&
differently when it is returned from the conversion function

operator derived&()

to what it does when it calls dereference function:

derived& operator*()

even if operator derived&() is rewritten in the clearer form

operator derived&() const {return operator*();}

the extra constructor is called.
Jul 22 '05 #5
lilburne wrote:

It looks like a gcc bug. The compiler is treating the returned derived&
differently when it is returned from the conversion function

operator derived&()

to what it does when it calls dereference function:

derived& operator*()

even if operator derived&() is rewritten in the clearer form

operator derived&() const {return operator*();}

the extra constructor is called.


Right, I have just reported to gcc it as a possible bug, and it recieved
Bugzilla number 14140.

I took the liberty of quoting your post in the bug report, I hope that
was okay.

/Christian

Jul 22 '05 #6
"John Harrison" <jo*************@hotmail.com> wrote in message news:<c0*************@ID-196037.news.uni-berlin.de>...
FWIW I believe that the position is this, compilers are allow to silently add or remove calls to copy constructors in certain circumstances (e.g.
creation of temporaries, return value optimisation) EVEN IF those copy
constructors have side effects. Essentially you must write your copy
constructors in such a way that you don't mind if they are called on the odd occasion when you weren't expecting it (or not called when you were
expecting it).


Hm. I'm not arguing with what you say, but that would essentially mean
that the behavior of any C++ program that contains a non-trivial copy
constructor is undefined. And since most real world C++ programs do,...


If the non-trivial copy constructor has a side effect then yes. But most
copy constructors (trivial or not) do nothing other than copy objects.


Are you using "undefined" in the strict, nasal-demon sense of the
word? Given this class and global variable:

int global = 0;

class foo
{
public:
foo(double d) : d_(d) {}
foo(const foo& other) : d_(other.d_) { ++global; }

private:
double d_;
};

there's no UB in copying foo objects is there? It's just that you've
no way of knowing what the value of 'global' will be after an
expression in which the copy constructor could be elided.

Since I don't write copy constructors with side effects, I am asking
purely out of academic interest.

--
GJD
Jul 22 '05 #7

"Gavin Deane" <de*********@hotmail.com> wrote in message
news:6d**************************@posting.google.c om...
"John Harrison" <jo*************@hotmail.com> wrote in message

news:<c0*************@ID-196037.news.uni-berlin.de>...

> FWIW I believe that the position is this, compilers are allow to

silently
> add or remove calls to copy constructors in certain circumstances (e.g. > creation of temporaries, return value optimisation) EVEN IF those copy > constructors have side effects. Essentially you must write your copy
> constructors in such a way that you don't mind if they are called on the
odd
> occasion when you weren't expecting it (or not called when you were
> expecting it).

Hm. I'm not arguing with what you say, but that would essentially

mean that the behavior of any C++ program that contains a non-trivial copy
constructor is undefined. And since most real world C++ programs do,...


If the non-trivial copy constructor has a side effect then yes. But most
copy constructors (trivial or not) do nothing other than copy objects.


Are you using "undefined" in the strict, nasal-demon sense of the
word? Given this class and global variable:

int global = 0;

class foo
{
public:
foo(double d) : d_(d) {}
foo(const foo& other) : d_(other.d_) { ++global; }

private:
double d_;
};

there's no UB in copying foo objects is there? It's just that you've
no way of knowing what the value of 'global' will be after an
expression in which the copy constructor could be elided.

Since I don't write copy constructors with side effects, I am asking
purely out of academic interest.

--
GJD


You're right, I think the standard calls this 'unspecified behaviour' not
undefined behaviour.

john
Jul 22 '05 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Christian Engström | last post by:
When I compile the below program with Microsoft Visual C++ version 6, I get the results I expect, which is that the program should write out base() derived() base() derived(derived) When I...
2
by: Siemel Naran | last post by:
This code fails compile std::auto_ptr<Base> f() { std::auto_ptr<Derived> out(new Derived()); return out; } There is ambiguity between a templated constructor and templated operator...
3
by: Tommi Mäkitalo | last post by:
Hi, I try to implement a factory for classes. There are 2 kinds of them, which have different constructors. One of them is the base class. The factory gets all needed parameters in his...
6
by: maadhuu | last post by:
The following is a piece of code and the output of the code is pasted after it . I dont understand how it works (while giving the output) .Can someone enlighten me on this ? thanking you ....
4
by: Alex Sedow | last post by:
Method invocation will consist of the following steps: 1. Member lookup (14.3) - evaluate method group set (Base.f() and Derived.f()) .Standart say: "The compile-time processing of a method...
4
by: tired_of_spaghetti | last post by:
I'm curious as to the need for the new keyword in an inherited method redefinition, so - Suppose I have a class hierachy that looks like public class Base { public virtual void myMethod()...
8
by: bonk | last post by:
When I have an instance of an object wich is of type System.Type, how can I find out if it directly or indirecly derives from another type? myTypeInstance == typeof(AnotherType) only seems to...
2
by: domehead100 | last post by:
I have a templated class, CDerived: template <typename TValue, typename TDraw, typename TEdit ...> class CDerived : public CBase { TValue m_Value public: TValue& GetValue() const {
2
by: itaj sherman | last post by:
The following does not compile on my VC6. Is it standard? #include <iostream> class Base { public: explicit Base() {
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.