c++/3167: Copyconstructor not called when entering function (var args)
philipp.bachmann@obtree.com
philipp.bachmann@obtree.com
Wed Jun 13 07:26:00 GMT 2001
>Number: 3167
>Category: c++
>Synopsis: Copyconstructor not called when entering function (var args)
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: unassigned
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Wed Jun 13 07:26:01 PDT 2001
>Closed-Date:
>Last-Modified:
>Originator: Philipp Bachmann
>Release: g++ 2.95.3
>Organization:
>Environment:
Sun Solaris 7 SPARC
>Description:
The code provided compiles successfully with the warnings:
[583]$ g++ copyconstr2.c++
copyconstr2.c++: In function `int ellipses(char *, ...)':
copyconstr2.c++:70: warning: cannot pass objects of type `base_t' through `...'
copyconstr2.c++:70: warning: cannot pass objects of type `base_t' through `...'
copyconstr2.c++: In function `int main()':
copyconstr2.c++:84: warning: cannot pass objects of type `base_t' through `...'
(These warnings are issued only if "base_t" explicitly has a copy
constructor defined.)
If the code is run, the following happens:
[584]$ ./a.out
"base_t::Constructor" called. Constructing 0xffbef2f0.
"main()": Secret is 42.
"ellipses()": Function entered.
"base_t::Copyconstructor" called. Constructing 0xffbef260.
"ellipses()": Strange: 42.
"ellipses()": Function ending.
"base_t::Destructor" called. Destroying 0xffbef260.
"main()": Function call over.
"base_t::Destructor" called. Destroying 0xffbef2f0.
If I understand, what's behind the scene, when calling a function, correctly, then I expect a call to
the copy constructor on entering the function, i.e. I would expect the hypothetical output
[584]$ ./a.out
"base_t::Constructor" called. Constructing 0xffbef2f0.
"main()": Secret is 42.
"base_t::Copyconstructor" called. Constructing 0xfoo.
"ellipses()": Function entered.
"base_t::Copyconstructor" called. Constructing 0xffbef260.
"ellipses()": Strange: 42.
"ellipses()": Function ending.
"base_t::Destructor" called. Destroying 0xffbef260.
"base_t::Destructor" called. Destroying 0xfoo.
"main()": Function call over.
"base_t::Destructor" called. Destroying 0xffbef2f0.
There is no reason in my opinion, why the compiler needs any information
about the argument types of the _function_ called (because there is a variable
argument list, there is indeed no such information on all arguments but the
first one) to call the copy constructor to put a copy of "base" onto
the stack - the only information, the compiler needs to have (and it has, because
"base" is defined as "base_t" two lines before the call to the
"ellipses()" function) for calling the copy constructor is the
type of "base".
The call to the copyconstructor that can be seen, though,
results from the initialization of local variable "base" inside
of the function "ellipses()" and can easily be switched off
by undefining "COPY". This is correct behaviour.
I've compared g++'s behaviour with the one of Sun CC 6 Update 1 (unpatched).
Sun's compiler calls the copyconstructor when entering the function, but has another bug:
It never destoys the space constructed...
>How-To-Repeat:
[583]$ g++ copyconstr2.c++
[584]$ ./a.out
>Fix:
>Release-Note:
>Audit-Trail:
>Unformatted:
----gnatsweb-attachment----
Content-Type: text/plain; name="copyconstr2.c++.txt"
Content-Disposition: inline; filename="copyconstr2.c++.txt"
/* Very simple program to show two bugs in two different compilers:
Sun Forte 6 Update 1 (unpatched) calls "base_t::base_t(const base_t &)"
on calling "ellipses("",CAST base)" even if "CAST" is replaced by
nothing - but will never call "base_t::~base_t(void)" to
destroy the copyconstructed formal parameter; if "CAST" is
defined to be "(base_t)", then "base_t::base_t(const base_t &)" is
called twice, but "base_t::~base_t(void)" is called only once to
destroy the temporary instance resulting from the cast operation.
GNU g++ 2.95.3, however, only calles "base_t::base_t(const base_t &)",
"on" entering the function, if the argument "base" in the function
call is explicitly casted to its own type; expected behaviour was
to always cast the copyconstructor at least once on entering
the function. */
/* $Log: copyconstr2.c++,v $
* Revision 1.2 2001/06/13 14:55:15 bachlipp
* Introduced "COPY" #define. Slightly presiced comment on
* g++ behaviour.
*
* Revision 1.1 2001/06/13 10:34:26 bachlipp
* Initial revision
* */
static const char rcsid[]="@@(#)$Id: copyconstr2.c++,v 1.2 2001/06/13 14:55:15 bachlipp Exp $";
#include<iostream>
#include<stdio.h>
#include<cstdarg>
#define CAST
// #define CAST (base_t)
#define COPY
class base_t {
public :
base_t(void);
base_t(const base_t &);
virtual ~base_t(void);
static const int secret;
};
base_t::base_t(void) {
std::cerr<<"\"base_t::Constructor\" called. Constructing "<<this<<"."<<std::endl;
}
base_t::base_t(const base_t &org) {
std::cerr<<"\"base_t::Copyconstructor\" called. Constructing "<<this<<"."<<std::endl;
}
base_t::~base_t(void) {
std::cerr<<"\"base_t::Destructor\" called. Destroying "<<this<<"."<<std::endl;
}
const int base_t::secret=42;
int ellipses(char *fmt, ...);
int ellipses(char *fmt, ...)
{
std::cerr<<"\"ellipses()\": Function entered."<<std::endl;
int retval;
va_list arg;
va_start(arg,fmt);
base_t base
#ifdef COPY
=va_arg(arg,base_t)
#else
; base=va_arg(arg,base_t)
#endif
;
retval=fprintf(stderr,"\"ellipses()\": Strange: %d.\n",base.secret);
va_end(arg);
std::cerr<<"\"ellipses()\": Function ending."<<std::endl;
return retval;
}
int main() {
base_t base;
std::cerr<<"\"main()\": Secret is "<<base.secret<<"."<<std::endl;
ellipses("",CAST base);
std::cerr<<"\"main()\": Function call over."<<std::endl;
return 0;
}
More information about the Gcc-bugs
mailing list