Exception Propagation / Copy Constructors

B

better_cs_now

Hello All,

Please consider the following:

#include <iostream>

using namespace std;

class Foo
{
public:
Foo()
{
cout << "Foo::Foo()" << endl;
}

~Foo()
{
cout << "Foo::~Foo()" << endl;
}

Foo(const Foo &)
{
cout << "Foo::Foo(const Foo &)" << endl;
}
};

void func3()
{
throw Foo();
}

void func2()
{
func3();
}

void func1()
{
func2();
}

int main()
{
try
{
func1();
}
catch(const Foo &)
{
cout << "Caught Foo" << endl;
}
}

This results in the following output:

Foo::Foo()
Caught Foo
Foo::~Foo()

This shows that the copy constructor does not run. Yet, if I make the
copy constructor private, the compiler balks with the following:

main.cpp: In function `void func3()':
main.cpp:20: error: `Foo::Foo(const Foo&)' is private
main.cpp:27: error: within this context
main.cpp:20: error: `Foo::Foo(const Foo&)' is private
main.cpp:27: error: within this context

This leads to two questions:

1. Why does the compiler balk about inaccessibility of a function (the
copy constructor) it does not use?

2. Why *is* it not using the copy constructor? I would have expected
to see the exception object copy constructed / destructed at each
level of the call stack as that stack is unwound.

Thanks,
Dave
 
P

pankaj

Hello All,

Please consider the following:

#include <iostream>

using namespace std;

class Foo
{
   public:
      Foo()
      {
         cout << "Foo::Foo()" << endl;
      }

      ~Foo()
      {
         cout << "Foo::~Foo()" << endl;
      }

      Foo(const Foo &)
      {
         cout << "Foo::Foo(const Foo &)" << endl;
      }

};

void func3()
{
   throw Foo();

}

void func2()
{
   func3();

}

void func1()
{
   func2();

}

int main()
{
   try
   {
      func1();
   }
   catch(const Foo &)
   {
      cout << "Caught Foo" << endl;
   }

}

This results in the following output:

Foo::Foo()
Caught Foo
Foo::~Foo()

This shows that the copy constructor does not run. Yet, if I make the
copy constructor private, the compiler balks with the following:

main.cpp: In function `void func3()':
main.cpp:20: error: `Foo::Foo(const Foo&)' is private
main.cpp:27: error: within this context
main.cpp:20: error: `Foo::Foo(const Foo&)' is private
main.cpp:27: error: within this context

This leads to two questions:

1. Why does the compiler balk about inaccessibility of a function (the
copy constructor) it does not use?

2. Why *is* it not using the copy constructor? I would have expected
to see the exception object copy constructed / destructed at each
level of the call stack as that stack is unwound.

Thanks,
Dave

I think the compiler is doing an optimization here by not creating and
destroying temporary object. The copy constructor still needs to be
accessible, because the optimization is compiler's choice and not a
mandatory behavior.
 
R

Richard Herring

In message
Hello All,

Please consider the following:

#include <iostream>

using namespace std;

class Foo
{
public:
Foo()
{
cout << "Foo::Foo()" << endl;
}

~Foo()
{
cout << "Foo::~Foo()" << endl;
}

Foo(const Foo &)
{
cout << "Foo::Foo(const Foo &)" << endl;
}
};

void func3()
{
throw Foo();
}

void func2()
{
func3();
}

void func1()
{
func2();
}

int main()
{
try
{
func1();
}
catch(const Foo &)
{
cout << "Caught Foo" << endl;
}
}

This results in the following output:

Foo::Foo()
Caught Foo
Foo::~Foo()

This shows that the copy constructor does not run. Yet, if I make the
copy constructor private, the compiler balks with the following:

main.cpp: In function `void func3()':
main.cpp:20: error: `Foo::Foo(const Foo&)' is private
main.cpp:27: error: within this context
main.cpp:20: error: `Foo::Foo(const Foo&)' is private
main.cpp:27: error: within this context

This leads to two questions:

1. Why does the compiler balk about inaccessibility of a function (the
copy constructor) it does not use?

Because, among other things, deliberately making it inaccessible is a
common way of preventing an object being copied. Not enforcing the
accessibility rule merely because of a compiler optimization would break
that.
2. Why *is* it not using the copy constructor? I would have expected
to see the exception object copy constructed / destructed at each
level of the call stack as that stack is unwound.

Why would you expect that, and what use would it be? Notionally, throw
Foo() initializes a temporary (15.1/3) (which is why an accessible copy
ctor is required) which gets passed directly to the catch block. It's
only automatic objects which get destroyed as the stack unwinds.
 
J

Juha Nieminen

1. Why does the compiler balk about inaccessibility of a function (the
copy constructor) it does not use?

Because the standard requires the copy constructor to be accessible
even though it specifically allows the compiler to skip calling it.

There's a much simpler situation with the same requirements: Suppose
that you have a class named MyClass with a constructor which takes an
int. If you do this:

MyClass obj = 5;

then the copy constructor of MyClass must be accessible even though the
compiler is allowed to never call it. Test it if you like.
2. Why *is* it not using the copy constructor? I would have expected
to see the exception object copy constructed / destructed at each
level of the call stack as that stack is unwound.

The compiler is allowed to optimize copy constructor calls away if it
can, even in situations where it should "logically" be called. The
standard specifically gives this permission. In this particular
situation the compiler uses some smart optimization to avoid useless
copy constructor calls.
 

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

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top