我们有一个广泛的代码库,目前使用原始指针,我希望迁移到unique_ptr。但是,许多函数期望原始指针作为参数,并且在这些情况下不能使用unique_ptr。我意识到我可以使用get()方法传递原始指针,但这会增加我必须触摸的代码行数,而且我发现它有点难看。我已经推出了我自己的unique_ptr,看起来像这样:
template <class T>
class my_unique_ptr: public unique_ptr <T>
{
public:
operator T*() { return get(); };
};
然后每当我向一个需要原始指针的函数parm提供my_unique_ptr时,它会自动将其转换为原始指针。
问题:这样做有什么本质上的危险吗?我原本以为这将是unique_ptr实现的一部分,所以我认为它的遗漏是故意的 - 有谁知道为什么?
答案 0 :(得分:7)
有很多丑陋的事情可能会因隐式转换而发生,例如:
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.
}
答案 1 :(得分:4)
与在get
上调用unique_ptr<>
相同,但会自动完成。在函数返回后,您必须确保指针未被存储/使用(因为unique_ptr<>
将在其生命周期结束时将其删除)。
还要确保不要在原始指针上调用delete
(甚至间接)。
另一件要确保的是你不创建另一个获取指针所有权的智能指针(例如另一个uniqe_ptr<>
) - 请参阅上面的删除注释
unique_ptr<>
没有自动为您进行转换(并且您明确调用get()
)的原因是为了确保您可以控制何时访问原始指针(以避免上述问题可能会无声地发生,否则)
答案 2 :(得分:2)
在unique_ptr
上提供隐式转换运算符(对原始指针)的主要“危险”源于unique_ptr
应该模拟单所有权语义的事实。这也是为什么无法复制unique_ptr
,但可以移动它。
考虑一下这种“危险”的例子:
class A {};
/* ... */
unique_ptr<A> a(new A);
A* a2 = a;
unique_ptr<A> a3(a2);
现在两个 unique_ptr
模型单一所有权语义指向的对象,以及自由世界的命运 - 不,宇宙 - - 悬而未决。
好吧,我有点戏剧性,但这就是主意。
就解决方法而言,我通常只需在指针上调用.get()
并完成它,小心识别我对got()
的所有权缺乏。
鉴于您有一个庞大的遗留代码库,您尝试使用unique_ptr
迁移,我认为您的转换包装器很好 - 但只是假设您和您的同事不做维护此代码时将来会出现错误。如果你有可能找到这种可能性(我通常会因为我是偏执狂),我会尝试改进所有现有代码以显式调用.get()
,而不是提供隐式转换。编译器将很乐意为您找到需要进行此更改的所有实例。
答案 3 :(得分:1)
在unique_ptr上使用强制转换操作符是危险的吗?
已修改查看评论
---不,它当然不应该是危险的--- 实际上标准要求隐式 {{1}转换为'safe bool'(请参阅Safe Bool Idiom)。
编辑说明:
新标准(也引入unique_ptr)引入了 explicit
强制转型。它仍适用于unique_ptr ,就像它是隐式转换一样,explicit operator T()
,if
,while
执行自动上下文转换布尔。
在我的辩护中,我的知识主要基于像Boost这样的C ++ 03库,其中做定义转换为for(;x;)
隐式
我希望这对其他人来说仍然有用。
(有关更多规范处理的其他答案,包括转换为原始指针)