Exception Propagation / Copy Constructors

Discussion in 'C++' started by better_cs_now@yahoo.com, Jun 18, 2009.

  1. Guest

    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
     
    , Jun 18, 2009
    #1
    1. Advertising

  2. pankaj Guest

    On Jun 18, 11:15 am, ""
    <> wrote:
    > 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.
     
    pankaj, Jun 18, 2009
    #2
    1. Advertising

  3. In message
    <>,
    "" <> writes
    >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.

    --
    Richard Herring
     
    Richard Herring, Jun 18, 2009
    #3
  4. wrote:
    > 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.
     
    Juha Nieminen, Jun 18, 2009
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    5
    Views:
    413
    E.J. Pitt
    Aug 26, 2005
  2. Jeremy Smith
    Replies:
    2
    Views:
    621
    Jeremy Smith
    Aug 3, 2006
  3. Jess
    Replies:
    5
    Views:
    640
    Ron Natalie
    Jun 7, 2007
  4. Brendon Costa
    Replies:
    0
    Views:
    814
    Brendon Costa
    Nov 3, 2007
  5. srp113
    Replies:
    3
    Views:
    495
Loading...

Share This Page