原始指针的 unique_ptr::reset 的等效实现?

Posted

技术标签:

【中文标题】原始指针的 unique_ptr::reset 的等效实现?【英文标题】:Equivalent implementation of unique_ptr::reset for raw pointers? 【发布时间】:2015-08-06 04:58:59 【问题描述】:

我正在尝试将一段代码重构为单独的对象/文件。为了保持相同的行为,我的代码需要使用指向原始文件中关键组件的指针,它们被声明为 unique_ptrs。

我正在考虑提取原始指针并将它们传递给我的对象,因为我的部分不负责删除任何指针。 (我希望我正确理解所有权语义,对于 C++ 来说还是比较新的)。唯一需要注意的是我需要复制 unique_ptr::reset 的行为。这段代码会做同样的事情重置吗?

template <typename Type>
void reset(Type* &current_ptr)
       Type* old_ptr = current_ptr;
       current_ptr = new Type();
       if(old_ptr != null)
           delete old_ptr;
 

【问题讨论】:

不要将智能指针视为指针,而是将它们视为资源所有权。资源是否一次只有一个所有者,然后使用unique_ptr;一个资源可以同时拥有多个所有者,然后使用shared_ptr。另外,如果您从unique_ptr 获取原始指针,并且unique_ptr 对象超出范围并删除指向的内存,您认为会发生什么?这会让你在不知情的情况下得到一个过时的指针。 那......绝对不是reset() 所做的。你到底想复制什么?如果您的原始代码调用reset(),则您正在删除指针。 如果您的部分不负责删除指针,那么您的部分将不想模拟std::unique_ptr::reset,因为这会删除std::unique_ptr 正在管理的指针。只要您不删除/重新分配它们,使用原始指针是正确的做法。这应该是拥有智能指针的工作。 底线是你不能在不使用实际的std::unique_ptr 的情况下执行 reset()。您无法使用 std::unique_ptr 管理的 原始指针 来实现它。 感谢大家的回答。原始代码确实调用了reset,我试图避免使用std::move,这似乎很麻烦,因为它需要移动~15 个ptr,然后再放回去。 【参考方案1】:

如果您需要调用reset,那么您实际上是在删除指针,并且在unique_ptr 的析构函数的上下文之外这样做会导致灾难(即使您的代码似乎可以工作,但可能仍然是未定义的行为)。

如果实际上您只需要取消引用(主要是 *-&gt;unique_ptr,那么您应该在新代码中传递并使用对对象的 reference,使确保 unique_ptr 在您使用引用时不会死。

如果您需要重新分配或重置智能指针,您将需要一种替代方法,但您没有在问题中提供足够的信息来帮助确定这种替代方法的范围。

【讨论】:

【参考方案2】:

不,reset() 不是这样做的。

正如 cmets 中所指出的,智能指针的特性是关于所有权,而不是指针本身。所有权意味着责任,因此如果unique_ptr 拥有一个对象,那么当unique_ptr 自己死亡时删除它是它的“工作”。 shared_ptr 稍微复杂一点,但它们也都是关于“在时机成熟时”删除对象,并从程序员身上卸下这个责任。

unique_ptrs 是唯一的,也就是说,任何两个unique_ptrs 都不应该拥有同一个对象。

现在,reset() 方法是一种表达方式:“嘿,unique_ptr,我有一个新指针要你管理,所以销毁旧指针(如果你有的话)并获得它的所有权我要给你一个新的。从现在开始,这是你自己死后要毁掉的那个。”

这个操作对原始指针没有意义,因为它们不拥有任何所有权,也不会在正确的时间或类似的情况下杀死自己。

因此,与您的代码相比,相似之处在于确实删除了旧指针。但除了本质缺失(即原始指针不记得删除自己,不持有所有权)之外,普通的reset()被赋予了一个指针,它并不会自己创建一个新对象。

【讨论】:

以上是关于原始指针的 unique_ptr::reset 的等效实现?的主要内容,如果未能解决你的问题,请参考以下文章

C++简单实现unique_ptr

std::unique_ptr::reset 重载问题

像自定义类一样构造的指针(内置类型)如何工作?

我啥时候想从原始指针构造一个共享指针

当原始指针和唯一指针都引用同一个对象时,如何避免双重释放?

将进程间管理的共享内存原始指针提升为类成员