Keeping object beyond current lexical scope

Discussion in 'C++' started by Urs Thuermann, Feb 21, 2012.

  1. How can I cleanly and elegantly keep a locally created object beyond
    the lexical block it is created in? Say I have a class Item with no
    default constructor, but a copy constructor and code like this:

    void some_func() {
    my_queue.lock();
    Item i = my_queue.get_item();
    my_queue.unlock();

    // do something with Item i
    }

    I now want to unlock() the my_queue even if get_item() throws an
    exception. But both, a try-catch block and RAII would make the
    variable Item i local so I cannot work on it after that block, e.g.

    void some_func () {
    // Cannot define Item i here since it has no default ctor.
    try {
    my_queue.lock();
    Item i = ...
    my_queue.unlock();
    } catch (...) {
    my_queue.unlock();
    }

    // cannot work with Item i here
    }

    I cannot define Item i before that block, since I have no default
    ctor. Adding such a ctor that leaves i mostly uninitialized and
    defining an assignment operator looks very unclean. Also something
    like this

    void some_func() {
    Item *i;
    try {
    ...
    i = new Item(my_queue.get_item());
    ...
    } catch ...
    ...
    }

    // do something with i

    delete i;
    }

    looks very unclean and cumbersome, unnecessarily creates dynamic
    memory overhead, and it also introduces the next resource leak if the
    "do something with i" can throw an exception.

    The cleanest solution I can currently think of is to put the try{}
    block into a separate function and to return the Item to some_func().

    Is there a simpler and cleaner way?


    urs
     
    Urs Thuermann, Feb 21, 2012
    #1
    1. Advertising

  2. On Feb 21, 12:08 pm, Urs Thuermann <> wrote:

    > How can I cleanly and elegantly keep a locally created object beyond
    > the lexical block it is created in?


    that's a contradictory requirement. Generally the options are for this
    sort of thing

    (a) make it static (hardly ever a good idea)
    (b) return a copy
    (c) dynamically allocate it

    > Say I have a class Item with no
    > default constructor, but a copy constructor and code like this:


    there's no sensible way you can provide a default CTOR?

    > void some_func() {
    >         my_queue.lock();
    >         Item i = my_queue.get_item();
    >         my_queue.unlock();
    >
    >         // do something with Item i
    >
    > }
    >
    > I now want to unlock() the my_queue even if get_item() throws an
    > exception.  But both, a try-catch block and RAII would make the
    > variable Item i local so I cannot work on it after that block, e.g.
    >
    > void some_func () {
    >         // Cannot define Item i here since it has no default ctor..
    >         try {
    >                 my_queue.lock();
    >                 Item i = ...
    >                 my_queue.unlock();
    >         } catch (...) {
    >                 my_queue.unlock();
    >         }
    >
    >         // cannot work with Item i here
    >
    > }
    >
    > I cannot define Item i before that block, since I have no default
    > ctor.  Adding such a ctor that leaves i mostly uninitialized and
    > defining an assignment operator looks very unclean.


    you've already got a copy CTOR... Big Three and all that...

    > Also something
    > like this
    >
    > void some_func() {
    >         Item *i;
    >         try {
    >                 ...
    >                 i = new Item(my_queue.get_item());
    >                 ...
    >         } catch ...
    >                 ...
    >         }
    >
    >         // do something with i
    >
    >         delete i;
    >
    > }
    >
    > looks very unclean and cumbersome, unnecessarily creates dynamic
    > memory overhead,


    is dynamic memory overhead that bad?

    > and it also introduces the next resource leak if the
    > "do something with i" can throw an exception.


    hold it in a smart pointer

    > The cleanest solution I can currently think of is to put the try{}
    > block into a separate function and to return the Item to some_func().
    >
    > Is there a simpler and cleaner way?


    either use dynamic allocation or pass is back as a value
     
    Nick Keighley, Feb 21, 2012
    #2
    1. Advertising

  3. Urs Thuermann

    Guest

    On Feb 21, 7:08 am, Urs Thuermann <> wrote:
    > How can I cleanly and elegantly keep a locally created object beyond
    > the lexical block it is created in?  Say I have a class Item with no
    > default constructor, but a copy constructor and code like this:
    >
    > void some_func() {
    >         my_queue.lock();
    >         Item i = my_queue.get_item();
    >         my_queue.unlock();
    >
    >         // do something with Item i
    >
    > }
    >
    > I now want to unlock() the my_queue even if get_item() throws an
    > exception.  But both, a try-catch block and RAII would make the
    > variable Item i local so I cannot work on it after that block, e.g.
    >
    > void some_func () {
    >         // Cannot define Item i here since it has no default ctor..
    >         try {
    >                 my_queue.lock();
    >                 Item i = ...
    >                 my_queue.unlock();
    >         } catch (...) {
    >                 my_queue.unlock();
    >         }
    >
    >         // cannot work with Item i here
    >
    > }
    >
    > I cannot define Item i before that block, since I have no default
    > ctor.  Adding such a ctor that leaves i mostly uninitialized and
    > defining an assignment operator looks very unclean.  Also something
    > like this
    >
    > void some_func() {
    >         Item *i;
    >         try {
    >                 ...
    >                 i = new Item(my_queue.get_item());
    >                 ...
    >         } catch ...
    >                 ...
    >         }
    >
    >         // do something with i
    >
    >         delete i;
    >
    > }
    >
    > looks very unclean and cumbersome, unnecessarily creates dynamic
    > memory overhead, and it also introduces the next resource leak if the
    > "do something with i" can throw an exception.
    >
    > The cleanest solution I can currently think of is to put the try{}
    > block into a separate function and to return the Item to some_func().
    >
    > Is there a simpler and cleaner way?
    >
    > urs


    You are actually asking the wrong question. You want to quarentee
    your unlock call gets called regardless of how you exit. What you do
    is use RAII in an object that locks you queue in it's constructor and
    unlocks it in it's destructor. This is a very common construct in
    threaded programs.

    Create a simple class that does just this and instantiate an object of
    the class right before you do you get item call. Now, whatever
    happens, your queue gets unlocked because your object is properly
    destructed regardless of how the function is exited.

    HTH
     
    , Feb 21, 2012
    #3
  4. "Urs Thuermann" wrote in message
    news:...
    >
    >How can I cleanly and elegantly keep a locally created object beyond
    >the lexical block it is created in? Say I have a class Item with no
    >default constructor, but a copy constructor and code like this:
    >
    >void some_func() {
    >my_queue.lock();
    > Item i = my_queue.get_item();
    >my_queue.unlock();
    >
    >// do something with Item i
    >}
    >
    >I now want to unlock() the my_queue even if get_item() throws an
    >exception.


    Can't you make a helper function

    Item get_item_with_lock() {
    ScopeLock_t Scope_Lock (my_queue);
    return my_queue.get_item();
    }

    In which ScopeLock_t is a class that locks in the constructor and unlocks in
    the destructor.
    Then:

    void some_func () {
    Item I = get_item_with_lock();

    // do something with i

    }
     
    Fred Zwarts \(KVI\), Feb 21, 2012
    #4
  5. Hi Urs

    Urs Thuermann wrote:

    > I now want to unlock() the my_queue even if get_item() throws an
    > exception. But both, a try-catch block and RAII would make the
    > variable Item i local so I cannot work on it after that block, e.g.


    class QueueLockUnLock
    {
    YourQueue *Queue;
    public:
    QueueLockUnLock(YourQueue *aQueue)
    : Queue(aQueue)
    {
    if( Queue )Queue->lock();
    }
    ~QueueLockUnLock()
    {
    UnLock();
    }
    void UnLock()
    {
    if( Queue )Queue->unlock();
    Queue = 0;
    }
    };

    void some_func() {
    QueueLockUnLock QueueLock( &my_queue );
    Item i = my_queue.get_item();
    QueueLock.UnLock();

    // do something with Item i
    }
     
    Asger Joergensen, Feb 21, 2012
    #5
  6. Urs Thuermann <> wrote:
    > How can I cleanly and elegantly keep a locally created object beyond
    > the lexical block it is created in? Say I have a class Item with no
    > default constructor, but a copy constructor and code like this:
    >
    > void some_func() {
    > my_queue.lock();
    > Item i = my_queue.get_item();
    > my_queue.unlock();
    >
    > // do something with Item i
    > }


    I don't really see what the problem is, because the solution is
    rather simple. It's the same as with eg. streams, where you can do
    this:

    void some_func()
    {
    std::istream is("something");
    Item i = whatever(is);
    is.close();

    // do something with i
    }

    The stream 'is' will be closed regardless of how the function is exited
    (because its destructor calls its close() function), but there's nothing
    stopping you from closing it "early", as above.

    Do the same with your lock object.
     
    Juha Nieminen, Feb 21, 2012
    #6
  7. Urs Thuermann

    K. Frank Guest

    Hello Urs!

    Unless I misunderstand something about your question, I don't
    think that your question is well posed.

    On Feb 21, 7:08 am, Urs Thuermann <> wrote:
    > How can I cleanly and elegantly keep a locally created object beyond
    > the lexical block it is created in?  Say I have a class Item with no
    > default constructor, but a copy constructor and code like this:
    >
    > void some_func() {
    >         my_queue.lock();
    >         Item i = my_queue.get_item();
    >         my_queue.unlock();
    >
    >         // do something with Item i
    >
    > }
    >
    > I now want to unlock() the my_queue even if get_item() throws an
    > exception.  But both, a try-catch block and RAII would make the
    > variable Item i local so I cannot work on it after that block, e.g.


    If get_item() throws, then you didn't get your Item, so there is no
    i to "do something" with whether you're in or out of local scope.

    > void some_func () {
    >         // Cannot define Item i here since it has no default ctor..
    >         try {
    >                 my_queue.lock();
    >                 Item i = ...
    >                 my_queue.unlock();
    >         } catch (...) {
    >                 my_queue.unlock();
    >         }
    >
    >         // cannot work with Item i here
    >
    > }


    I would rewrite some_func as follows:

    The point is that i is only guaranteed to be valid inside the try
    block, so you should work with it there.

    void some_func () {
    // Cannot define Item i here since it has no default ctor.
    <-- okay
    try {
    my_queue.lock();
    Item i = my_queue.get_item(); // <-- get_item might
    throw, okay
    my_queue.unlock(); // <-- lock is released as soon
    as possible
    do_something_with_i (i); // <-- get_item didn't throw
    so you have a valid i
    } catch (...) {
    my_queue.unlock(); // <-- release lock, even if
    get_item throws, okay
    }

    // cannot work with Item i here <-- true, but if get_item
    threw, i is no good anyway
    }

    Now this approach does require two copies of the line
    "my_queue.unlock;".
    I don't think that's a big deal, but you avoid this issue with RAII.
    If
    you want to use RAII to manage the lock, I don't see a way to do it
    without
    introducing the helper function that Fred suggested.

    >
    > I cannot define Item i before that block, since I have no default
    > ctor.  Adding such a ctor that leaves i mostly uninitialized and
    > defining an assignment operator looks very unclean.  Also something
    > like this
    >
    > void some_func() {
    >         Item *i;
    >         try {
    >                 ...
    >                 i = new Item(my_queue.get_item());
    >                 ...
    >         } catch ...
    >                 ...
    >         }
    >
    >         // do something with i


    You have the same issue here. If get_item throws you don't have a
    valid Item, and i is now a bad pointer. You only know that i is
    good inside of the try block.

    >
    >         delete i;
    >
    > }
    >
    > looks very unclean and cumbersome, unnecessarily creates dynamic
    > memory overhead, and it also introduces the next resource leak if the
    > "do something with i" can throw an exception.
    >
    > The cleanest solution I can currently think of is to put the try{}
    > block into a separate function and to return the Item to some_func().


    Still, possibly, the same issue. What should your "separate function"
    return if the call to get_item throws?

    > Is there a simpler and cleaner way?
    >
    > urs


    Sorry if I misunderstood the issue.


    Good luck.


    K. Frank
     
    K. Frank, Feb 21, 2012
    #7
    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. Matt Knepley

    Lexical Scope

    Matt Knepley, Oct 30, 2003, in forum: Python
    Replies:
    3
    Views:
    429
    Paul Clinch
    Oct 30, 2003
  2. Replies:
    18
    Views:
    496
    Bengt Richter
    Dec 17, 2005
  3. globalrev

    python: lexical or dynamic scope?

    globalrev, May 13, 2008, in forum: Python
    Replies:
    3
    Views:
    882
    Mark Wooding
    May 14, 2008
  4. mrstevegross

    Weird behavior with lexical scope

    mrstevegross, Nov 6, 2008, in forum: Python
    Replies:
    8
    Views:
    249
    Lawrence D'Oliveiro
    Nov 7, 2008
  5. Xah Lee
    Replies:
    0
    Views:
    2,246
    Xah Lee
    Feb 26, 2009
Loading...

Share This Page