Copy constructor VC++ compiler bug
It seems to me that I found a bug in Visual C++ compiler.
The thing is about copy constructor in context of throwing.
As the Standard specifies [15.1 Throwing an exception, points 3-5]
thrown object is copied to a temporary object. This temporary may be
eliminated if eliminating it only removes a call to copy constructor
and destructor for it. But removed or not the type of thrown object
must be copyable (by constructor) and destructible (both functions must
be accessible in the appropriate context) otherwise program is
ill-formed.
For testing I used Visual 6.0 (a little bit), Visual C++ 2003 Toolkit,
Visual C++ 2005 .NET (both used with options /Wall /EHsc) and Cygwin
(used with options -Wall).
Here is the first bug.
Lets consider code like:
----------------------------------------
#include <iostream>
using namespace std;
class a {
public:
a() {
cout << "a::a()" << endl;
}
~a() {
cout << "a::~a()" << endl;
}
private:
a(const a&) {
cout << "a::a(const a&)" << endl;
}
};
int main(int, char*[]) {
try {
a obj;
throw obj;
} catch(const a&) {
cout << "caught!" << endl;
}
return 0;
}
----------------------------------------
This code is ill-formed according to the Standard (inaccessible copy
constructor).
1) Visual C++ 2003 produced compilation error due to inaccessibility of
copy constructor.
2) Visual C++ 2005 compiled and linked (without even a warning!) and
during execution used the copy constructor as if it was not private.
3) Cygwin produced compilation error due to inaccessibility of copy
constructor.
Why Visual C++ 2005 made this mistake? Especially that 2003 did
recognize this as code error.
This is dangerous but still correct program is compiled and executed
correctly so that is not so bad. However further investigations lead to
even worser problem.
Lets consider now this code:
----------------------------------------
#include <iostream>
using namespace std;
class a {
public:
a() {
cout << "a::a()" << endl;
}
~a() {
cout << "a::~a()" << endl;
}
a(const a&);
};
class b : public a {
public:
b() : a() {
cout << "b::b()" << endl;
}
~b() {
cout << "b::~b()" << endl;
}
b(const b&) : a() {
cout << "b::b(const b&)" << endl;
}
};
int main(int, char*[]) {
try {
b obj;
throw obj;
} catch(const b&) {
cout << "caught!" << endl;
}
return 0;
}
----------------------------------------
This code is correct according to Standard. The accessibility of copy
constructor of class a is of no importance here because it is never
used (thrown object is of class b and it has accessible and defined
copy constructor which does not use copy constructor of class a).
1) Visual C++ 2003 produced linking error due to the lack of the
definition of copy constructor of class a.
2) Visual C++ 2005 made the same.
3) Cygwin made everything correctly.
It seems that Visual C++ tries to use the copy constructor of class a
even when it is not needed at all. And a very interesting thing. If we
make this copy constructor private (which should not change anything in
this example) then 2003 works correctly and 2005 still produces the
same error.
But if we define the body of this feral copy constructor (private or
not) then both Visual compilers do everything correctly and during
execution copy constructor of class a is not used (as it should be).
This makes their behavior even more nonsense.
I found this during the process of moving a project from Visual 6.0 to
Visual 2005 (and made a few experiments afterwards). The code compiled
(linked and worked...) fine on 6.0 but produced linking error on 2005.
I had there a class derived from MFC CObject which was then thrown in a
few places. CObject has a private copy constructor and does not define
its body (naturally) so I received the linking error as in the example
above.
I know that I can change CObject to CException. I can also remove the
inheritance. But I cannot (I'm just a programmer, the decision is not
to be taken by me :)). So what to do?
Because I think that I understand the Standard correctly (at least in
this part) and Cygwin seems to confirm this the question is why Visual
does not work correctly and even more, why from the version 6.0 through
the 2003 version to the 2005 version there was no progress but a
regress instead.
Are there any hopes for a patch?
Adam Badura