question on freestore management

Discussion in 'C++' started by spipyeah, Aug 20, 2003.

  1. spipyeah

    spipyeah Guest

    In the C++ FAQ Lite, it is said in question 16.9:

    If an exception occurs during the Fred constructor of p = new Fred(),
    the C++ language guarantees that the memory sizeof(Fred) bytes that
    were allocated will automagically be released back to the heap.

    Naturally, any locally declared objects in the class are destroyed as
    the stack is unwound. But what about objects allocated in the
    constructor using new?

    I totally expect the answer to be that you have to delete them
    yourself. I just want to be 100% sure.

    So given class Fred, the following would be necessary in Fred's
    constructor, right?

    class Fred
    {
    public:
    Fred();

    Joe *p;
    }

    Fred::Fred()
    {
    try
    {
    joe = new Joe();
    // do some more stuff
    }
    catch( ... )
    {
    // must manually delete joe
    delete joe;
    throw;
    }
    }


    Thank you.
    spipyeah, Aug 20, 2003
    #1
    1. Advertising

  2. spipyeah

    tom_usenet Guest

    On 20 Aug 2003 04:12:27 -0700, (spipyeah) wrote:

    >In the C++ FAQ Lite, it is said in question 16.9:
    >
    >If an exception occurs during the Fred constructor of p = new Fred(),
    >the C++ language guarantees that the memory sizeof(Fred) bytes that
    >were allocated will automagically be released back to the heap.
    >
    >Naturally, any locally declared objects in the class are destroyed as
    >the stack is unwound. But what about objects allocated in the
    >constructor using new?
    >
    >I totally expect the answer to be that you have to delete them
    >yourself. I just want to be 100% sure.


    Yup, this is the case. This is why a single class should typically
    only manage one concept.

    >
    >So given class Fred, the following would be necessary in Fred's
    >constructor, right?
    >
    >class Fred
    >{
    >public:
    > Fred();
    >
    > Joe *p;


    Joe* joe;

    >}
    >
    >Fred::Fred()
    >{
    > try
    > {
    > joe = new Joe();
    > // do some more stuff
    > }
    > catch( ... )
    > {
    > // must manually delete joe
    > delete joe;
    > throw;
    > }
    >}


    That code is incorrect, since it might try to delete an uninitialized
    value of joe (if the call to new Joe throws). Instead:

    Fred::Fred()
    :joe(0)
    {
    try
    {
    joe = new Joe();
    // do some more stuff that might throw

    }
    catch( ... )
    {
    // must manually delete joe
    delete joe;
    throw;
    }
    }

    Note that you can put try catch blocks around the initializer list.
    The following complicated example demonstrates why it isn't generally
    a good idea to manage more than one pointer in a class. e.g.

    #include <stdexcept>
    #include <iostream>

    class Joe
    {
    public:
    static int count;
    Joe()
    {
    if ((++count % 2) == 0)
    throw std::runtime_error("Joe threw");
    }
    };

    int Joe::count = 0;

    class Fred
    {
    public:
    Joe* joe;
    Joe* schmoe;
    Fred(Joe* newJoe);
    ~Fred();
    };

    Fred::Fred(Joe* newJoe)
    try : joe(newJoe), schmoe(new Joe)
    {
    try
    {
    throw std::runtime_error("Fred threw");
    }
    catch(...)
    {
    std::cout << "In constructor body catch\n";
    delete schmoe;
    throw;
    }
    }
    catch(...)
    {
    std::cout << "In constructor initializer catch\n";
    //schmoe initialization threw
    delete joe;
    throw;
    }

    Fred::~Fred()
    {
    delete joe;
    delete schmoe;
    }

    int main()
    {
    try
    {
    Fred fred(new Joe);
    }
    catch(std::exception const& e)
    {
    std::cout << "in main " << e.what() << "\n\n";
    }

    try
    {
    Fred fred(0);
    }
    catch(std::exception const& e)
    {
    std::cout << "in main " << e.what() << "\n\n";
    }
    }


    The smart pointer version of Fred is much simpler:

    class Fred
    {
    public:
    shared_ptr<Joe> joe;
    shared_ptr<Joe> schmoe;
    Fred(Joe* newJoe);
    };

    Fred::Fred(Joe* newJoe)
    :joe(newJoe), schmoe(new Joe)
    {
    throw std::runtime_error("Fred threw");
    }

    Tom
    tom_usenet, Aug 20, 2003
    #2
    1. Advertising

  3. spipyeah

    spipyeah Guest

    Thank you for your answers Tom.

    > Yup, this is the case. This is why a single class should typically
    > only manage one concept.


    Would you mind expanding a bit on this?
    spipyeah, Aug 25, 2003
    #3
    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. Scott
    Replies:
    4
    Views:
    363
    Scott
    Oct 12, 2003
  2. Jorge Rivera
    Replies:
    10
    Views:
    5,655
    John Harrison
    May 10, 2004
  3. Tomás

    From the freestore

    Tomás, Mar 24, 2006, in forum: C++
    Replies:
    3
    Views:
    295
    Tomás
    Mar 24, 2006
  4. Philipp

    Freestore allocation etc

    Philipp, Sep 4, 2006, in forum: C++
    Replies:
    18
    Views:
    451
    Philipp
    Sep 6, 2006
  5. yonil
    Replies:
    3
    Views:
    365
    yonil
    Oct 6, 2006
Loading...

Share This Page