【发布时间】:2016-12-20 01:19:39
【问题描述】:
假设我想编写一个接收指针的函数。但是我想允许调用者使用裸指针或智能指针——无论他们喜欢什么。这应该很好,因为我的代码应该依赖于指针语义,而不是指针的实际实现方式。这是执行此操作的一种方法:
template<typename MyPtr>
void doSomething(MyPtr p)
{
//store pointer for later use
this->var1 = p;
//do something here
}
上面将使用鸭子类型,可以传递裸指针或智能指针。当传递的值是基指针时会出现问题,我们需要看看我们是否可以转换为派生类型。
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
}
}
以上代码适用于原始指针,但不适用于智能指针,因为我需要使用dynamic_pointer_cast 而不是dynamic_cast。
上述问题的一个解决方案是我添加了新的实用程序方法,例如 universal_dynamic_cast,通过使用 std::enable_if 选择重载版本,它适用于原始指针和智能指针。
我的问题是,
- 添加所有这些复杂性以使代码支持原始指针和智能指针是否有价值?或者我们应该在我们的库公共 API 中使用
shared_ptr吗?我知道这取决于库的用途,但是在 API 签名中使用shared_ptr的一般感觉是什么?假设我们只需要支持 C++11。 - 为什么 STL 没有内置的指针转换,它不知道您传递的是原始指针还是智能指针?这是 STL 设计人员故意的还是只是疏忽?
- 上述方法的另一个问题是智能感知和可读性的损失。这显然是所有鸭子类型代码中的问题。然而,在 C++ 中,我们有一个选择。我可以轻松地在上面输入我的论点,例如
shared_ptr<MyBase>,这会牺牲调用者传递任何指针中包含的任何内容的灵活性,但我的代码的读者会更有信心,并且可以在应该输入的内容上建立更好的模型。在 C++ 中公共图书馆 API,是否存在一种或另一种一般偏好/优势? - 我在其他 SO 答案中看到了另一种方法,作者建议您应该只使用
template<typename T>并让调用者决定 T 是某种指针类型、引用还是类。如果我必须在 T 中调用某些东西,这种超级通用方法显然不起作用,因为 C++ 需要取消引用指针类型,这意味着我可能必须使用 create utility method likeuniversal_deref将 * 运算符应用于指针类型但对普通对象没有任何作用。我想知道是否有任何设计模式可以更轻松地实现这种超级通用方法。再一次,最重要的是,是否值得解决所有这些麻烦,或者只是保持简单并在任何地方使用shared_ptr?
【问题讨论】:
-
(*p)->someMember()取消引用太多了。我想你的意思是p->someMember(),或者,如果出于某种原因你想更详细一点,(*p).someMember()。 -
@IgorTandetnik - 哎呀,对不起。固定。
-
似乎设计了很多复杂性只是为了引起混乱。让您的 API 采用一种已知类型并坚持使用它!
-
您通常可以使用
&*b或std::addressof(*b)来获取底层原始指针,以更加迂腐。这至少适用于原始指针、标准智能指针和迭代器。然后dynamic_cast指向你内心深处的原始指针。 -
你一直在使用“通用”这个词,但你显然只有原始指针和
std::shared_ptr。例如。我看不出你假设的universal_dynamic_cast将如何与std::unique_ptr一起工作,在这种情况下,你不能有两个实例持有指向同一个对象的指针。
标签: c++ c++11 smart-pointers