C++ API中的智能指针?

Mik*_*lya 5 c++ api smart-pointers c++11

除了一些罕见的情况之外,通常建议不要在现代C++中使用原始指针.在C++库API中使用智能指针的常见做法是什么?

以下用例出现在我的脑海中:

  1. 返回新对象的函数.
  2. 一个返回新对象的函数,但它还创建了对该对象的另一个引用.
  3. 仅使用它接收的对象作为参数的函数.
  4. 接管对象所有权的函数.
  5. 一个函数,它将存储对作为参数接收的对象的引用,但可能存在对同一对象的其他引用(来自调用方).

Mat*_* M. 13

不幸的是,库API设计远远超出了语言本身的规则:突然你必须关心实现细节,比如ABI.

与C相反,常见的实现可以轻松地一起交互,C++实现具有非常不同的ABI(用于VC++的Microsoft ABI与gcc和Clang使用的Itanium ABI完全不兼容),并且C++标准库实现也彼此不兼容,因此如果std::类出现在接口中,那么使用libstdc ++(与gcc捆绑)编译的库不能被使用另一个主要版本的libstdc ++的程序或其他实现(如libc ++(与Clang捆绑))使用.

因此,它实际上取决于您是否希望将库作为二进制文件提供,或者假设用户可以使用自己的编译器和选择的标准库实现来编译库.只有在后一种情况下,你应该暴露一个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>

  • 请注意,库 C 二进制 API 可以包装在由客户端编译的仅标头 C++ API 中。 (2认同)
  • @Yakk:当你有一个核心 C++ 实现公开一个 C API(为了二进制稳定性)并决定将它包装在一个只有头文件的 C++ API 中(为了便于使用)时,这开始变得有趣了 :) (2认同)

Mik*_*lya 6

  1. 在一般情况下,唯一指针可以完成工作.

    std::unique_ptr<Foo> func();
    
    Run Code Online (Sandbox Code Playgroud)

    这样您就可以将它们直接分配给auto调用者站点的变量,而不用担心内存管理.

    auto u = func();
    
    Run Code Online (Sandbox Code Playgroud)

    如果您需要共享所有权,您可以在调用者站点上转换智能指针:

    std::shared_ptr<Foo> s{func()};
    
    Run Code Online (Sandbox Code Playgroud)

    但是,如果函数的返回类型不是多态的,并且该类型移动速度很快,您可能更喜欢按值返回:

    Foo func();
    
    Run Code Online (Sandbox Code Playgroud)
  2. 共享指针.

    std::shared_ptr<Foo> func();
    
    Run Code Online (Sandbox Code Playgroud)
  3. 只需使用对象的引用或const引用,在调用者站点上使用原始指针或智能指针"取消引用".

    void func(Foo& obj);
    void func(const Foo& obj);
    
    Run Code Online (Sandbox Code Playgroud)

    如果参数是可选的,您可以使用原始指针,以便您可以轻松地将nullptr它们传递给它们.

    void func(Foo *obj);
    void func(const Foo *obj);
    
    Run Code Online (Sandbox Code Playgroud)
  4. 独特的指针.

    void func(std::unique_ptr<Foo> obj);
    
    Run Code Online (Sandbox Code Playgroud)
  5. Const对共享指针的引用.

    void func(const std::shared_ptr<Foo>& obj);
    
    Run Code Online (Sandbox Code Playgroud)

    const引用(对共享指针)只是一个优化,以防止在调用函数和返回时调整引用计数.

  • 除非由于某种原因你想跟踪`shared_ptr`的状态(即它的引用计数),否则我看不出#5的任何原因.您应该只存储对实际对象的引用. (2认同)
  • @MiklósHomolya我不确定用户如何实现这一目标.你有一个例子吗?无论如何,我仍然认为按值返回应该是默认情况. (2认同)