We have an extensive code base which currently uses raw pointers, and I'm hoping to migrate to unique_ptr. However, many functions expect raw pointers as parameters and a unique_ptr cannot be used in these cases. I realize I can use the get() method to pass the raw pointer, but this increases the number of lines of code I have to touch, and I find it a tad unsightly. I've rolled my own unique_ptr which looks like this:
template <class T>
class my_unique_ptr: public unique_ptr <T>
{
public:
operator T*() { return get(); };
};
Then every time I provide a my_unique_ptr to a function parm which expects a raw pointer, it automagically turns it into the raw pointer.
Question: Is there something inherently dangerous about doing this? I would have thought this would have been part of the unique_ptr implementation, so I'm presuming its omission is deliberate - does anyone know why?
There's a lot of ugly things that can happen on accident with implicit conversions, such as this:
std::unique_ptr<resource> grab_resource()
{return std::unique_ptr<resource>(new resource());}
int main() {
resource* ptr = grab_resource(); //compiles just fine, no problem
ptr->thing(); //except the resource has been deallocated before this line
return 0; //This program has undefined behavior.
}
It is the same as invoking the get
on the unique_ptr<>
, but it will be done automatically. You will have to make sure the pointer is not stored/used after the function returns (as unique_ptr<>
will delete it when its lifetime ends).
Also make sure you don't call delete
(even indirectly) on the raw pointer.
Yet another thing to make sure is that you do not create another smart pointer that takes ownership of the pointer (e.g. another uniqe_ptr<>
) -- see delete note above
The reason for unique_ptr<>
not doing the conversion for you automatically (and have you call get()
explicitly) is to ensure you have control over when you access the raw pointer (to avoid the above issues that could happen silently otherwise)
The main "danger" in providing an implicit conversion operator (to a raw pointer) on a unique_ptr
stems from the fact that unique_ptr
is supposed to model single-ownership semantics. This is also why it's not possible to copy a unique_ptr
, but it can be moved.
Consider an example of this "danger":
class A {};
/* ... */
unique_ptr<A> a(new A);
A* a2 = a;
unique_ptr<A> a3(a2);
Now two unique_ptr
s model single-ownership semantics over the object pointed to, and the fate of the free world -- nay, the universe -- hangs in the balance.
OK, I'm being a bit dramatic, but that's the idea.
As far as workarounds go, I would normally just call .get()
on the pointer and be done with it, being careful to recognize a lack of ownership on what I just got()
.
Given that you have a large, legacy code-base that you are trying to migrate to using unique_ptr
, I think your conversion wrapper is fine -- but only assuming you and your co-workers don't make mistakes in the future when maintaining this code. If that is a possibility you find likely (and I normally would because I'm paranoid), I would try to retrofit all existing code to call .get()
explicitly instead of providing an implicit conversion. The compiler will happily find all the instances for you where this change needs to be made.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With