假设我想编写接受指针的函数。但是我想让调用者使用裸指针或智能指针——无论他们喜欢什么。这应该很好,因为我的代码应该依赖于指针语义,而不是指针的实际实现方式。这是执行此操作的一种方法:
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
选择重载版本,它同时适用于原始指针和智能指针.
我的问题是,
- 添加所有这些复杂性以使代码支持原始指针和智能指针是否有值(value)?或者我们应该只使用
shared_ptr
在我们的图书馆公共(public) API 中?我知道这取决于图书馆的用途,但使用shared_ptr
的一般感觉如何?遍及 API 签名?假设我们只需要支持 C++11。 - 为什么 STL 没有内置的指针转换,它不知道您传递的是原始指针还是智能指针?这是 STL 设计者有意为之还是疏忽大意?
- 上述方法中的另一个问题是失去智能感知和一点可读性。这显然是所有鸭子类型代码中的问题。然而,在 C++ 中,我们有一个选择。我本可以很容易地在上面输入我的论点,比如
shared_ptr<MyBase>
这会牺牲调用者的灵 active 来传递任何指针中包含的任何内容,但我的代码的读者会更有信心并且可以根据应该传入的内容构建更好的模型。在 C++ 公共(public)库 API 中,是否有一般偏好/优势的一种方式或另一个? - 我在其他 SO 答案中看到了另一种方法,作者建议您只使用
template<typename T>
并让调用者决定 T 是某种指针类型、引用还是类。如果我必须在 T 中调用某些东西,这种 super 通用方法显然不起作用,因为 C++ 需要取消引用指针类型,这意味着我可能必须 create utility method likeuniversal_deref
使用std::enable_if
将 * 运算符应用于指针类型,但对普通对象不执行任何操作。我想知道是否有任何设计模式可以更轻松地允许这种 super 通用方法。同样,最重要的是,是否值得去解决所有这些麻烦,或者只是保持简单并使用shared_ptr
无处不在?
最佳答案
存储shared_ptr
在一个类中具有语义意义。这意味着该类现在声称拥有该对象:对其销毁负责。在shared_ptr
的情况下,您可能会与其他代码分担该责任。
存储裸T*
……好吧,这没有明确的含义。核心 C++ 指南告诉我们不应使用裸指针来表示对象所有权,但其他人做了不同的事情。
根据核心准则,您所说的是一个函数,该函数可能会或可能不会根据用户调用对象的方式声明对对象的所有权。我会说你有一个非常困惑的界面。所有权语义通常是代码基本结构的一部分。函数要么取得所有权,要么不取得所有权;它不是根据调用位置来确定的。
但是,有时(通常出于优化原因)您可能需要这样做。你可能有一个对象,在一个实例中被赋予内存所有权,而在另一个实例中却没有。这通常会出现字符串,其中一些用户会分配一个您应该清理的字符串,而其他用户将从静态数据(如文字)中获取字符串,因此您不会清理它。
在那些情况下,我会说你应该开发一个具有这种特定语义的智能指针类型。它可以从 shared_ptr<T>
构建或 T*
.在内部,它可能会使用 variant<shared_ptr<T>, T*>
或类似类型,如果您无权访问 variant
.
然后你可以给它自己的dynamic/static/reinterpret/const_pointer_cast
功能,将根据内部 variant
的状态根据需要转发操作.
或者,shared_ptr
实例可以被赋予一个什么也不做的删除器对象。因此,如果您的界面仅使用 shared_ptr
,用户可以选择传递技术上并不真正拥有的对象。
关于c++ - 编写更通用的指针代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41233534/