Exception caught inside a constructor

Discussion in 'C++' started by Jarek Blakarz, Jul 9, 2013.

  1. Hi

    The following program throws an exception while allocating "A" object.
    Allocation fails. An exception is caught inside "C" constructor.
    "C" destructor releases memory for both objects. Segmentation fault
    occurs while releasing memory for object "A" since the memory has actually not
    been allocated for that object.

    Please help me to modify the program to work correctly. I want all exceptions
    to be caught inside a "C" constructor and no memory leak should happen.

    I am aware that this problem may be solved by wrapping ptrA and ptrB in a smart
    pointers but I am not interested in this solution.

    Thanks for help.

    #include <iostream>

    using namespace std;

    struct A {
    A(void)
    {
    cout << "A" << endl;
    }

    ~A(void)
    {
    cout << "~A" << endl;
    }

    void* operator new(size_t size)
    {
    cout << "A new" << endl;
    throw 10; // allocation fails
    return ::eek:perator new(size);
    }
    };

    struct B {
    B(void)
    {
    cout << "B" << endl;
    }

    ~B(void)
    {
    cout << "~B" << endl;
    }
    };

    struct C {
    B *ptrB;
    A *ptrA;

    C(void)
    {
    cout << "C" << endl;
    try {
    ptrB = new B;
    } catch(...) {
    cout << "new B - exception" << endl;
    }
    try {
    ptrA = new A;
    } catch(...) {
    cout << "new A - exception" << endl;
    }
    }

    ~C(void) {
    cout << "~C" << endl;
    delete ptrB;
    delete ptrA;
    }
    };

    int main(void)
    {
    try {
    C c;
    } catch(...) {
    cout << "main exception handler" << endl;
    }
    }
    Jarek Blakarz, Jul 9, 2013
    #1
    1. Advertising

  2. On 7/9/2013 11:08 AM, Drew Lawson wrote:
    > In article <>
    > Jarek Blakarz <> writes:
    >> Hi
    >>
    >> The following program throws an exception while allocating "A" object.
    >> Allocation fails. An exception is caught inside "C" constructor.
    >> "C" destructor releases memory for both objects. Segmentation fault
    >> occurs while releasing memory for object "A" since the memory has actually not
    >> been allocated for that object.

    >
    > That isn't exactly what your problem is.
    >
    >> struct C {
    >> B *ptrB;
    >> A *ptrA;
    >>
    >> C(void)
    >> {

    >
    > At this point, both ptrB and ptrA are uninialized pointers.
    > They probably have junk for values.
    >
    >> cout << "C" << endl;
    >> try {
    >> ptrB = new B;
    >> } catch(...) {
    >> cout << "new B - exception" << endl;
    >> }
    >> try {
    >> ptrA = new A;
    >> } catch(...) {
    >> cout << "new A - exception" << endl;
    >> }

    >
    > If those threw, 'new' never returned, and no assignment was made,
    > so the pointers are still junk.
    >
    >> }
    >>
    >> ~C(void) {
    >> cout << "~C" << endl;
    >> delete ptrB;
    >> delete ptrA;

    >
    > And here, you pass junk to delete.
    >
    >> }
    >> };
    >>
    >> int main(void)
    >> {
    >> try {
    >> C c;
    >> } catch(...) {
    >> cout << "main exception handler" << endl;
    >> }
    >> }

    >
    > You should clear the pointers before anything has a chance of going wrong:
    >
    > C() : ptrA(0), ptrB(0)
    > {
    > // do the c'tor details
    > }
    >
    > (Others will now tell you not to use pointers.)


    Why?

    And why not do

    C() : ptrA(new A), ptrB(new B) {}

    at all? If the latter throws, the former memory will be deallocated (I
    think that's guaranteed by the Standard, let somebody correct me if I'm
    wrong), and the object will not have been constructed at all, so no
    d-tor shall be called...

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Jul 9, 2013
    #2
    1. Advertising

  3. On 7/9/2013 1:27 PM, Paavo Helde wrote:
    > Victor Bazarov <> wrote in
    > news:krha4v$pun$:
    >
    >> On 7/9/2013 11:08 AM, Drew Lawson wrote:
    >>> In article <>
    >>> Jarek Blakarz <> writes:
    >>>> Hi
    >>>>
    >>>> The following program throws an exception while allocating "A"
    >>>> object. Allocation fails. An exception is caught inside "C"
    >>>> constructor. "C" destructor releases memory for both objects.
    >>>> Segmentation fault occurs while releasing memory for object "A"
    >>>> since the memory has actually not been allocated for that object.
    >>>
    >>> That isn't exactly what your problem is.
    >>>
    >>>> struct C {
    >>>> B *ptrB;
    >>>> A *ptrA;
    >>>>
    >>>> C(void)
    >>>> {
    >>>
    >>> At this point, both ptrB and ptrA are uninialized pointers.
    >>> They probably have junk for values.
    >>>
    >>>> cout << "C" << endl;
    >>>> try {
    >>>> ptrB = new B;
    >>>> } catch(...) {
    >>>> cout << "new B - exception" << endl;
    >>>> }
    >>>> try {
    >>>> ptrA = new A;
    >>>> } catch(...) {
    >>>> cout << "new A - exception" << endl;
    >>>> }
    >>>
    >>> If those threw, 'new' never returned, and no assignment was made,
    >>> so the pointers are still junk.
    >>>
    >>>> }
    >>>>
    >>>> ~C(void) {
    >>>> cout << "~C" << endl;
    >>>> delete ptrB;
    >>>> delete ptrA;
    >>>
    >>> And here, you pass junk to delete.
    >>>
    >>>> }
    >>>> };
    >>>>
    >>>> int main(void)
    >>>> {
    >>>> try {
    >>>> C c;
    >>>> } catch(...) {
    >>>> cout << "main exception handler" << endl;
    >>>> }
    >>>> }
    >>>
    >>> You should clear the pointers before anything has a chance of going
    >>> wrong:
    >>>
    >>> C() : ptrA(0), ptrB(0)
    >>> {
    >>> // do the c'tor details
    >>> }
    >>>
    >>> (Others will now tell you not to use pointers.)

    >>
    >> Why?
    >>
    >> And why not do
    >>
    >> C() : ptrA(new A), ptrB(new B) {}
    >>
    >> at all? If the latter throws, the former memory will be deallocated
    >> (I think that's guaranteed by the Standard, let somebody correct me if
    >> I'm wrong),

    >
    > Yes, I think this is wrong. The constructed subobjects are destroyed
    > automatically if there is an exception during the next subobject
    > construction. However, here the subobject in question is a raw pointer
    > ptrA, whose destroy is a non-op. The C++ compiler is not so smart (and
    > should not be!) to figure out how to execute parts of the C destructor
    > code if something goes wrong during the construction.
    >
    > That's why it is bad to use pointers.


    OK, so I must have confused this situation with some other, like
    constructing subobjects or members that have their own overloaded 'new'
    operator (or something like that).

    Oh well, shows how much experience using pointers I have... So, kids,
    either learn to use pointers for those rare moments when you do need to
    use them, or find any way not to use them at all, ever. :)

    V
    --
    I do not respond to top-posted replies, please don't ask
    Victor Bazarov, Jul 9, 2013
    #3
  4. Jarek Blakarz wrote:

    > Please help me to modify the program to work correctly. I want all
    > exceptions to be caught inside a "C" constructor and no memory leak
    > should happen.


    Drew showed you one way for this.

    > I am aware that this problem may be solved by wrapping ptrA and ptrB
    > in a smart pointers but I am not interested in this solution.


    However, IMO this is the better way, even if you don't want to use
    standard smart pointers. Rather than having C manage memory for A and B,
    have a "memory manager" encapsulate all this. (OTOH, this is more or
    less what std::unique_ptr does. You're trying to de-encapsulate what it
    does and replicate it "manually" in C. There are reasons why placing
    this code into a RAII class is the better choice.)

    Gerhard
    Gerhard Fiedler, Jul 9, 2013
    #4
  5. Jarek Blakarz

    Stuart Guest

    Jarek Blakarz writes:
    >> Hi
    >>
    >> The following program throws an exception while allocating "A" object.
    >> Allocation fails. An exception is caught inside "C" constructor.
    >> "C" destructor releases memory for both objects. Segmentation fault
    >> occurs while releasing memory for object "A" since the memory has actually not
    >> been allocated for that object.


    On 07/09/13, Drew Lawson wrote:
    > That isn't exactly what your problem is.


    [snip]

    > You should clear the pointers before anything has a chance of going wrong:
    >
    > C() : ptrA(0), ptrB(0)
    > {
    > // do the c'tor details
    > }
    >
    > (Others will now tell you not to use pointers.)


    Do not use pointers.

    Regards,
    Others
    Stuart, Jul 9, 2013
    #5
  6. Jarek Blakarz

    Luca Risolia Guest

    Drew Lawson wrote:

    > You should clear the pointers before anything has a chance of going wrong:
    >
    > C() : ptrA(0), ptrB(0)
    > {
    > // do the c'tor details
    > }


    Some compilers might complain about ptrB being initialized after ptrA, since
    ptrB is declared before ptrA.

    In C++11 I'd write:

    struct C {
    B *ptrB = nullptr;
    A *ptrA = nullptr;
    C() { // ...
    Luca Risolia, Jul 9, 2013
    #6
  7. Jarek Blakarz

    Casey Guest

    On Tuesday, July 9, 2013 9:33:38 AM UTC-5, Jarek Blakarz wrote:
    > The following program throws an exception while allocating "A" object.
    > Please help me to modify the program to work correctly. I want all exceptions
    > to be caught inside a "C" constructor and no memory leak should happen.


    Use smart pointers. Failing that:

    #include <iostream>

    using namespace std;

    struct A {
    A(void)
    {
    cout << "A" << endl;
    }

    ~A(void)
    {
    cout << "~A" << endl;
    }

    void* operator new(size_t size)
    {
    cout << "A new" << endl;
    throw 10; // allocation fails
    return ::eek:perator new(size);
    }
    };

    struct B {
    B(void)
    {
    cout << "B" << endl;
    }

    ~B(void)
    {
    cout << "~B" << endl;
    }
    };

    struct C {
    B *ptrB;
    A *ptrA;

    C(void)
    {
    cout << "C" << endl;
    try {
    ptrB = new B;
    } catch(...) {
    cout << "new B - exception" << endl;
    throw;
    }
    try {
    ptrA = new A;
    } catch(...) {
    cout << "new A - exception" << endl;
    delete ptrB;
    throw;
    }
    }

    ~C(void) {
    cout << "~C" << endl;
    delete ptrB;
    delete ptrA;
    }
    };

    int main(void)
    {
    try {
    C c;
    } catch(...) {
    cout << "main exception handler" << endl;
    }
    }
    Casey, Jul 11, 2013
    #7
  8. Jarek Blakarz

    Cholo Lennon Guest

    On 07/09/2013 11:33 AM, Jarek Blakarz wrote:
    > Hi
    >
    > The following program throws an exception while allocating "A" object.
    > Allocation fails. An exception is caught inside "C" constructor.
    > "C" destructor releases memory for both objects. Segmentation fault
    > occurs while releasing memory for object "A" since the memory has actually not
    > been allocated for that object.
    >
    > Please help me to modify the program to work correctly. I want all exceptions
    > to be caught inside a "C" constructor and no memory leak should happen.
    >
    > I am aware that this problem may be solved by wrapping ptrA and ptrB in a smart
    > pointers but I am not interested in this solution.
    >
    > Thanks for help.
    >
    > #include <iostream>
    >
    > using namespace std;
    >
    > struct A {
    > A(void)
    > {
    > cout << "A" << endl;
    > }
    >
    > ~A(void)
    > {
    > cout << "~A" << endl;
    > }
    >
    > void* operator new(size_t size)
    > {
    > cout << "A new" << endl;
    > throw 10; // allocation fails
    > return ::eek:perator new(size);
    > }
    > };
    >
    > struct B {
    > B(void)
    > {
    > cout << "B" << endl;
    > }
    >
    > ~B(void)
    > {
    > cout << "~B" << endl;
    > }
    > };
    >
    > struct C {
    > B *ptrB;
    > A *ptrA;
    >
    > C(void)
    > {
    > cout << "C" << endl;
    > try {
    > ptrB = new B;
    > } catch(...) {
    > cout << "new B - exception" << endl;
    > }
    > try {
    > ptrA = new A;
    > } catch(...) {
    > cout << "new A - exception" << endl;
    > }
    > }
    >
    > ~C(void) {
    > cout << "~C" << endl;
    > delete ptrB;
    > delete ptrA;
    > }
    > };
    >
    > int main(void)
    > {
    > try {
    > C c;
    > } catch(...) {
    > cout << "main exception handler" << endl;
    > }
    > }
    >


    You could use a function-try block in your C ctor (in your example B
    doesn't throw any exception so you are pretty sure that the caught
    exception was raised by A):

    ....
    struct C {
    B *ptrB;
    A *ptrA;

    C()
    try
    : ptrB(new B)
    , ptrA(new A)
    {
    cout << "C" << endl;
    }
    catch(int) {
    delete ptrB;
    }

    ...
    };

    int main()
    {
    try {
    C c;
    }
    catch(int) {
    cout << "main exception handler" << endl;
    }
    }


    Regards


    --
    Cholo Lennon
    Bs.As.
    ARG
    Cholo Lennon, Jul 11, 2013
    #8
    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. Ola
    Replies:
    0
    Views:
    519
  2. Tedka
    Replies:
    2
    Views:
    2,653
    Mr. Dot Net
    Jul 19, 2004
  3. Paul Dale
    Replies:
    1
    Views:
    280
    Rocco Moretti
    Sep 22, 2005
  4. Generic Usenet Account
    Replies:
    10
    Views:
    2,194
  5. Christian Hackl
    Replies:
    4
    Views:
    350
    James Kanze
    Aug 1, 2008
Loading...

Share This Page