Re: C++ Exception and Copy Constructor requirement
Hi Alex,
Your catch code is actually incorrect and I hope that is a typo. If you
catch by value, it will definitely require another copy, thus the copy
cater. In Herb Sutter and Scott Meyers' publications, it is recommended to
throw by value, as you have done, and catch by reference. Never catch by
value as it will cause slicing and extra copying. I hope that was a typo.
<code>
My code is like this:
// Exception's
class CExcept {
WORD m_dwError;
public:
CExcept(WORD err) : m_dwError(err) { }
WORD Error() const { return m_dwError; }
private:
CExcept( const CExcept & from ) : m_dwError( from.m_dwError )
{ ATLTRACE( _T("Copy cater\n") ); }
private:
CExcept & operator=( const CExcept & rhs ); // no implementation
};
// main program
void Foo() {
throw CExcept(100);
}
void G() { Foo(); }
void Test() {
try {
G();
}
catch( CExcept &e ) {
ATLTRACE( _T("Exception caught\n") );
}
}
int _tmain( int argc, _TCHAR* argv[] ) {
Test();
return 0;
}
</code>
Now if you comment out the implementation of the private copy cater of
CExcept and include just a declaration, the standard way of blocking
copying, just like that for the operator=(), the compilation is still
successful. But the linker fails as it cannot find the implementation.
With the code above, you should not see the trace "Copy C'tor" after a run.
If you put a break point there, it does not stop. If that is the case, why
demands the implementation?
I have used protected constructor. I have used private cater to support
factory methods with more revealing names. But never has the need to use a
private copy cater.
That's the puzzling bit and I hope someone can shed some light on this. The
moral of the story is that your exception class must provide a copy cater,
otherwise the compiler provided one may not work as required.
Leon
"Alex Blekhman" <tkfx.REMOVE@yahoo.com> wrote in message
news:#fJNahCaKHA.5608@TK2MSFTNGP05.phx.gbl...
"Leon" wrote:
Using VC2003:
The compiler demands a public declaration of a copy constructor otherwise
the compiler will tell you that you cannot throw that exception. In the
absence of the implementation, the linker reports unresolved externals.
Fair enough.
This is the correct behavior.
Using VC2005 & VC2008
The linker demands an implementation of the copy constructor of the
exception, even if it is a private copy constructor. The compiler does
not complain at all.
Could you provide some code that exposes this problem? I cannot reproduce
it with my VC++2008. Here is the code I tried:
<code>
class X
{
public:
X() {}
~X() {}
private:
X(const X&);
};
int foo(int a)
{
if(a == 1)
throw X();
return a + 5;
}
int main()
{
int res = 0;
try
{
res = foo(rand() % 2);
}
catch(X x)
{
cout << &x;
}
return res;
}
</code>
Compiler correctly complains about inaccessible copy constructor. If I
comment out the copy c'tor declaration, then the code compiles and runs
fine as it should.
Questions:
1) For all these built, the copy constructor is NEVER called. I put a
trace there and I put a break point in a non-trivial copy constructor. I
cannot see the trace nor the debugger breaking in the copy constructor.
What is happening?
According to 15.1/5
<quote>
If the use of the temporary object can be eliminated without changing the
meaning of the program except for the execution of constructors and
destructors associated with the use of the temporary object (12.2), then
the exception in the handler can be initialized directly with the argument
of the throw expression.
</quote>
So, the behavior is similar to returning an object by value from a
function: compiler checks the availability of copy c'tor and destructor,
but can avoid actually calling them.
2) What is the use of the implementation of a private copy constructor?
The only thing that can use it is a member function of the exception. The
throw statement cannot use it. So why did VC2005/VC2008 was happy with
that?
Friends of such class (both functions and classes) will be able to create
copies of the class. However, I should admit that I cannot recall any
useful case for this quirk.
Alex