Keeping object beyond current lexical scope

U

Urs Thuermann

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
 
N

Nick Keighley

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
 
A

AnonMail2005

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
 
F

Fred Zwarts \(KVI\)

"Urs Thuermann" wrote in message
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

}
 
A

Asger Joergensen

Hi Urs

Urs said:
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
}
 
J

Juha Nieminen

Urs Thuermann said:
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.
 
K

K. Frank

Hello Urs!

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

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
 

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

No members online now.

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,836
Latest member
login dogas

Latest Threads

Top