编写更通用的指针代码

Shi*_*hah 6 c++ smart-pointers c++11

假设我想编写一个接收指针的函数.但是我想允许调用者使用裸指针或智能指针 - 无论他们喜欢什么.这应该是好的,因为我的代码应该依赖于指针语义,而不是指针实际实现的方式.这是一种方法:

template<typename MyPtr>
void doSomething(MyPtr p)
{
    //store pointer for later use
    this->var1 = p;

    //do something here
}
Run Code Online (Sandbox Code Playgroud)

上面将使用duck typing并且可以传递裸指针或智能指针.当传递的值是基指针时我们需要查看是否可以转换为派生类型.

template<typename BasePtr, typename DerivedPtr>
void doSomething(BasePtr b)
{
    auto d = dynamic_cast<DerivedPtr>(b);
    if (d) {
        this->var1 = d;

        //do some more things here
    }
}
Run Code Online (Sandbox Code Playgroud)

上面的代码适用于原始指针,但不适用于智能指针,因为我需要使用dynamic_pointer_cast而不是dynamic_cast.

上面问题的一个解决方案是我添加了一个新的实用工具方法,类似于universal_dynamic_cast通过选择使用的重载版本在原始指针和智能指针上工作std::enable_if.

我的问题是,

  1. 添加所有这些复杂性是否有价值,因此代码支持原始指针和智能指针?或者我们应该shared_ptr在我们的库公共API中使用?我知道这取决于库的目的,但是使用shared_ptr所有API签名的一般感觉是什么?假设我们只需要支持C++ 11.
  2. 为什么STL没有内置指针强制转换,无论你是否传递原始指针或智能指针?这是故意的STL设计师还是只是疏忽?
  3. 上述方法中的另一个问题是智能感知的丢失和可读性的缺失.这显然是所有鸭类型代码中的问题.但是,在C++中,我们有一个选择.我可以很容易地在上面强烈地输入我的论点,就像shared_ptr<MyBase>会牺牲灵活性来让调用者传递包含在任何指针中的任何东西,但是我的代码的读者会更自信,并且可以在应该进入的内容上构建更好的模型.在C++公共库API中,是否有这样或那样的一般偏好/优势?
  4. 我在其他SO回答中看到了另一种方法,作者提出你应该只使用template<typename T>并让调用者决定T是否是某种指针类型或引用或类.如果我必须在T中调用某些东西,这种超级泛型方法显然不起作用,因为C++需要解除引用指针类型,这意味着我必须创建实用程序方法,例如universal_deref使用std::enable_if将*运算符应用于指针类型但不对普通对象执行任何操作.我想知道是否有任何设计模式可以更容易地实现这种超级通用方法.最重要的是,是否值得去解决所有这些问题,或者只是保持简单并shared_ptr随处使用?

Joh*_*its 1

我认为您想要的解决方案是强制函数的调用者传递常规指针而不是使用模板函数。使用shared_ptrs是一个很好的实践,但是在沿着堆栈传递时没有任何好处,因为该对象已经被函数的调用者保存在共享指针中,保证它不会被销毁,并且您的函数并不是真正“保存”上”到对象。当存储为成员时(或实例化将存储在成员中的对象时),但不作为参数传递时,请使用shared_ptrs。无论如何,调用者从shared_ptr 获取原始指针应该是一件简单的事情。

  • @ShitalShah:那么那些“类接口和方法”需要知道它们存储的*类型*的指针。存储“unique_ptr”的接口与存储“shared_ptr”的接口看起来有很大不同。甚至这也与存储“T*”的不同。您不应该尝试设计这样的界面,这些界面对它们所存储的内容视而不见。 (2认同)