C++ API 中的智能指针
Smart pointers in C++ APIs?
经常建议不要在现代C++中使用原始指针,除了极少数情况。在C++库 API 中使用智能指针的常见做法是什么?
我想到了以下用例:
- 返回新对象的函数。
- 返回一个新对象的函数,但它也创建了对该对象的另一个引用。
- 仅使用它作为参数接收的对象的函数。
- 接管对象所有权的函数。
- 一个函数,它将存储对它作为参数接收的对象的引用,但可能存在对同一对象的其他引用(从调用方)。
不幸的是,库 API 设计远远超出了语言本身的规则:突然间你必须关心实现细节,例如 ABI。
与 C 相反,在 C 中,常见的实现可以很容易地交互在一起,C++实现具有非常不同的 ABI(Microsoft VC++ 的 ABI 与 gcc 和 Clang 使用的 Itanium ABI 完全不兼容),并且C++标准库实现也彼此不兼容,因此使用 libstdc++ 编译的库(与 gcc 捆绑在一起)不能被使用另一个主要版本的 libstdc++ 或其他实现(如 libc++(与 Clang 捆绑在一起)的程序使用,如果 界面中将显示std::
类。
因此,这实际上取决于您是希望将库作为二进制文件交付,还是假设用户能够使用自己的编译器和所选的标准库实现来编译库。只有在后一种情况下,你才应该公开一个C++接口,因为二进制发行版坚持使用 C 更好(而且与其他语言集成也更容易)。
有了这个,让我们假设你决定使用C++ API:
如果1) 返回新对象的函数。
对象可以按值返回,则这样做;如果它是多态的,请使用 std::unique_ptr<Object>
。
2) 返回一个新对象的函数,但它也创建了对该对象的另一个引用。
罕见的情况。我想你的意思是它以某种方式保留了一个参考。在这种情况下,您拥有共享所有权,因此显而易见的选择是 std::shared_ptr<Object>
.
3) 仅使用它收到的对象作为参数的函数。
比最初看起来要复杂得多,即使假设没有保留对对象的引用。
- 通常,通过引用传递(
const
或不传递) - 除非您打算对对象的副本进行操作,在这种情况下,按值传递以从潜在的移动中受益
4)接管对象所有权的函数。
简单所有权:std::unique_ptr<Object>
。
5) 一个函数,它将存储对它作为参数接收的对象的引用,但可能还有其他对同一对象的引用(从调用方)。
共享所有权:std::shared_ptr<Object>
-
在一般情况下,唯一的指针可以完成这项工作。
std::unique_ptr<Foo> func();
这样您就可以将它们直接分配给调用方站点的
auto
变量,而不必担心内存管理。auto u = func();
如果您需要共享所有权,您可以在呼叫者站点上转换智能指针:
std::shared_ptr<Foo> s{func()};
但是,如果函数的返回类型不是多态的,并且该类型移动速度很快,则您可能更喜欢按值返回:
Foo func();
-
共享指针。
std::shared_ptr<Foo> func();
-
只需使用对对象的引用或常量引用,在调用方站点"取消引用"原始指针或智能指针。
void func(Foo& obj); void func(const Foo& obj);
如果参数是可选的,则可以使用原始指针,以便可以轻松地将
nullptr
传递给它们。void func(Foo *obj); void func(const Foo *obj);
-
独特的指针。
void func(std::unique_ptr<Foo> obj);
-
对共享指针的常量引用。
void func(const std::shared_ptr<Foo>& obj);
const 引用(对共享指针)只是一种优化,用于防止在调用函数和返回函数时调整引用计数。
这是一个非常古老的问题,但也是一个重要的问题。
答案中缺少的一个思想流派是,如果可以帮助它,则不应从API返回原始指针或智能指针。
已经讨论了原始指针问题。 但是智能指针也可能被滥用,尤其是在具有复杂内部 API 的大型项目中。
解决方法是创建一个 RAII/包装器对象来保存(从未公开的)智能指针。
- 1d 智能指针不适用于语法 (*)++
- 优先顺序:智能指针和类析构函数
- 对于C++中使用智能指针的指针算术限制,有没有一种变通方法
- 智能指针作为无序映射键,并通过引用进行比较
- 智能指针概念所有权和寿命
- 正在理解智能指针,但出现错误:未分配正在释放的指针
- 尝试使用智能指针时引发异常
- 我可以制作指向智能指针的智能指针吗?
- 通过智能指针和转换对基本模板参数进行模板推导
- OpenCV 我应该使用智能指针来防止内存泄漏吗?
- 从堆栈分配的原始指针构造智能指针
- 初始化指向类实例的智能指针并访问其方法
- 如何使用 std::make_shared 创建基类类型的智能指针?
- 给定一个指向堆分配内存的指针,智能指针实现如何为其找到合适的释放函数?
- 编译器不会使用 -std=c++11 编译智能指针
- 具有智能指针的多态性
- C++:矢量分配器行为、内存分配和智能指针
- 在什么情况下,需要共享智能指针而无法使用唯一指针?
- 指向函数签名中的常量智能指针
- 使用智能指针附加的继承对象的深层复制