有通用的智能指针吗?

3
我最近了解了各种智能指针类型,特别是unique_ptr将非常有用,shared_ptr与weak_ptr也在一定程度上很有用。然而,我不确定如何创建可以处理任何指针类型的“通用”函数,以及是否这样做是个好主意。
假设你有一个由智能指针封装的对象向量,并且你想使用一个函数对所有元素应用某些操作,类似于以下内容:
void doSomething(vector<shared_ptr<SomeType>>& array) {
   // iterate over all array elements and do something
}

显然,你需要复制这个函数三次,分别针对shared_ptr、unique_ptr和weak_ptr,这有点繁琐。更好的方法是使用“通用”或“多态”的智能指针类型,以适应所有这些类型作为函数参数使用:

void doSomething(vector<generic_ptr<SomeType>>& array) {
   // iterate over all array elements and do something
   // no matter if array is a vector<shared_ptr> or vector<unique_ptr>
}

那么,是否存在这样的智能指针?如果有的话-使用它可能会出现哪些问题?如果没有-为什么没有?

4个回答

4
不同的指针类型允许使用不同的所有权处理方式,需要不同的运行时开销。在您的情况下,您可以使用模板:

template<typename TVector>
void doSomething(TVector& array) {
   // iterate over all array elements and do something
}

对于所有智能(和不太智能)指针,使用通用的operator*operator->


我想知道类似 template<typename generic_ptr> void doSomething(vector<generic_ptr<SomeType>>& array) 这样的代码是否可行。 - Bernhard Barker
@Dukeling 通过使用 template<template<class> class generic_ptr, class SomeType> void doSomething(vector<generic_ptr<SomeType>>& array) 可能会解决问题,但我不知道它有什么用处。 - alexrider
2
@Dukeling:这太荒谬了。如果容器更改为deque怎么办?如果用户有一个带有非标准分配器的向量呢?在整个容器类型上进行模板化更自然。 - Kerrek SB
1
你可能想将模板参数命名为 RangeOfPointersToSomeType 或类似的名称,以向读者表明 doSomething 函数将对元素进行解引用,并期望在其末尾找到一个 SomeType - Steve Jessop
@KerrekSB 那么您也许可以以同样的方式对容器进行模板化,但我确实看到了潜在的问题(如果未来更改导致问题,则更改2行并不是什么大问题)。虽然从安全编码的角度来看这对我来说很有意义-您传递给函数的类型不正确的可能性较小,这可能会引发可能具有隐晦性的错误或在某些情况下实际编译。但是,Steve更好地命名参数的建议可能更实用。 - Bernhard Barker

4

一些误解导致了尴尬的代码风格:

  1. 智能指针与裸指针一样通用:在调用所指对象的函数时,您可以将它们作为同类对待。如果您真的需要将它们传递给接受裸指针的函数(而且这些函数不会拥有智能指针),则可以使用它们的 get() 函数来获取指针。参见 3。

  2. 操作集合的函数不应将集合作为参数,而应该是一个模板,其中包含一对迭代器,然后通过取消迭代器所指向的指针,给您提供对真实对象的引用。

  3. 不要编写具有裸指针参数的函数。改用引用,并在调用站点上取消引用。我知道这并非总是可能的,但大多数情况下都是。

替代在函数中循环的方法是使该函数作用于单个对象(引用),并将循环放在调用站点。C++11 使此非常简洁:

void some_function(item_type& item); // const if necessary
for(auto&& item_ptr : collection_of_item_smart_ptrs)
  some_function(*item_ptr);

不用任何语法或风格上的困扰,清晰地表达意图、目的和类型。


0

所有这些指针类型实际上都包装了一个裸指针。因此我们有两种情况:

  1. 您的方法以某种方式修改指针。在这种情况下,您将无法将其概括为应该根据类型有不同的情况。

  2. 您从未修改指针。只需将const裸指针传递给函数即可。


0

每种智能指针类型都有自己的使用模式。

  • unique_ptr 不能放在容器中,它既不可复制也不可复制赋值

  • weak_ptr 必须转换为 shared_ptr 才能访问引用对象。例如可用于缓存,但在各处使用时不方便。

  • 在您的情况下,shared_ptr 是最好的选择。


2
当您拥有符合要求的unique_ptr时,您就处于C++11世界中,然后您可以将不可复制、不可复制分配的类型存储在容器中,前提是它们是可移动的。 unique_ptr是可移动的。 - CB Bailey
2
@Charles Bailey:您说得完全正确。使用C++11版本是完美的选择。我总是想知道为什么人们在涉及C(++)时总是假设你指的是旧标准,而不是现有版本(即使并非所有功能都在所有编译器中都可用)。 - Askaga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接