Reputation: 91
If function Foo()
transfers ownership of std::unique_ptr
to function Bar()
and say Bar()
throws an exception, object contained in std::unique_ptr
will get destroyed.
How can one handle a case where Foo()
might want to keep the ownership with itself in such cases.
class A
{
public:
std::unique_ptr<SomeData> getSomeData(...);
};
class B
{
public:
pushToQ(std::unique_ptr<SomeData>);
doSomething()
...
popFromQ();
...
};
Now if B::pushToQ()
throws QueueFullException
I will loose the data generated by getSomeData()
which I might not want.
Upvotes: 0
Views: 453
Reputation: 302767
You're either transferring ownership - or you're not. If you want to transfer, then you shouldn't care if Bar
can throw and kill your object:
// i do not care what bar does with ptr, i am done with it
bar(std::move(ptr));
If you might want to retain ownership maybe, then transferring ownserhip is the wrong solution. Either you want to pass your unique_ptr
by reference, or maybe just pull out the raw pointer, or maybe even just use a shared_ptr
. It depends on your use-case. But there's no half-way ownership transfer.
Here are some examples. Which is preferred is entirely up to you:
bar(std::unique_ptr<Data>& ptr) {
// not transferring, caller still owns the data
something_that_might_throw();
something_that_might_not();
// ok got here?
std::unique_ptr<Data> myPtr = std::move(ptr);
// MINE NOW!!!
}
The above is "the ONLY exception safe solution to moving a unique_ptr into a container in an exception safe manner with a strong guarantee that the system won't be corrupted" (from MGetz)
Or:
bar(Data* ptr) {
// it really doesn't matter, caller always owns the data
// just don't go doing something like this
std::unique_ptr<Data> awful_idea(ptr);
// now two separate people both think they own the data
// and will both try to delete it. That'll work the first time...
}
Or a strictly better version so you can't mess it up unless you try really hard
bar(Data& data) {
// well clearly the caller owns it
}
Or:
bar(std::shared_ptr<Data> ptr) {
// we both share the data
// it won't get deleted until both bar() and caller delete it
}
Upvotes: 6
Reputation: 42554
In the called function, store the unique_ptr
in the thrown exception object. If the callee - or some other function up the call stack - wants to save it, it can then be extracted. If not, it will be safely destroyed.
Upvotes: 1
Reputation: 385104
Then don't transfer the ownership.
Pass a SomeData&
into Bar()
, instead.
Upvotes: 2
Reputation: 44238
You can use std::shared_ptr
instead of std::unique_ptr
and release your instance if pushToQ() succeded, keep your copy otherwise.
Upvotes: 1