我应该使用哪个智能指针
Which smart pointer should I use?
我正在研究一个由许多不同类型(Properties、Parent、Child等)组成的模型。每种类型都与c api中的一组函数相关联。例如:
Type "Properties":
char* getName(PropertiesHandle);
char* getDescription(PropertiesHandle);
Type "Parent"
PropertiesHandle getProperties(ParentHandle);
ChildHanlde getFirstChild(ParentHandle);
Type "Child"
PropertiesHandle getProperties(ChildHandle);
ParentHanlde getParent(ChildHandle);
ChildHandle getNextChild(ChildHandle);
我为这个C api库创建了一组C++接口,如下所示:
class IProperties
{
public:
virtual std::string getName() = 0;
virtual std::string getDescription() = 0;
};
class IParent
{
public:
virtual std::shared_ptr<IProperties> getProperties() = 0;
virtual std::shared_ptr<IChild> getFirstChild() = 0;
};
class IChild
{
public:
virtual std::shared_ptr<IProperties> getProperties() = 0;
virtual std::shared_ptr<IParent> getParent() = 0;
virtual std::shared_ptr<IChild> getNextChild() = 0;
};
然后,我通过类Properties、Parent和Child实现这些接口。
因此,Child实例将通过其构造函数获取其特定的ChildHandle,其getParent函数将如下所示:
std::shared_ptr<IParent> getParent()
{
// get the parent handle and wrap it in a Parent object
return std::shared_ptr<IParent>(new Parent(_c_api->getParent(_handle)));
}
在你看来,我在这里返回shared_ptr合理吗。我不能使用std::unique_ptr,因为Google Mock要求模拟方法的参数和返回值是可复制的。我通过Google Mock在测试中嘲笑这些界面。
我也在思考未来如何优化,这可能会带来循环引用的可能性。如果使用缓存来避免对C api的多次调用(例如,子级不需要多次建立其父级),并使用child构造函数获取其父级,则可能会导致这种情况。这将需要使用weak_ptrs,这将更改接口和我的许多代码。。。
关键问题是:返回指针的语义是什么?
-
如果返回的父/子/属性对象的生存期与返回的(可能在某种意义上是拥有的)对象无关,则返回
shared_ptr
是合理的:这表明调用者和被调用者具有决定对象生存期的平等权利std::shared_ptr<IChild> child = parent->getFirstChild(); // now I can keep child around ... if parent is destroyed, one // orphaned subtree is magically kept around. Is this desirable?
-
如果返回的对象的生存期依赖于被调用者自己的生存期,则:
shared_ptr
将错误地暗示调用者将返回对象的生存期延长到被调用者的生存期之外是有意义的unique_ptr
会错误地建议转让所有权- raw指针没有明确地做出任何误导性的承诺,但也没有给出任何关于正确使用的提示
因此,如果调用者只是获得对对象内部状态的工作引用,而没有转移所有权或延长对象生存期,则不建议使用任何智能指针。
考虑只返回一个引用。
返回shared_ptr
没有错,但我会努力让您相信这可能不是最好的选择。
通过使用智能指针,您获得了安全性的优势,但API的用户失去了使用最适合其需求的智能指针类型的灵活性,而不得不始终使用shared_ptr
。
这也取决于你有多重视安全而不是灵活性,但我个人会考虑返回一个裸指针,并允许用户使用他想要的智能指针。当然,如果出于某种原因需要我使用shared_ptr
,我会的。
shared_ptr
很好,但它确实为最终用户提供了一些限制,例如C++11支持。原始指针,或者允许他们定制智能指针的特性,可以为最终用户提供更大的灵活性。
不管指针是什么,我建议小心实现引入的语义。在当前的实现中,每个访问器调用都实例化一个新的包装,等价性检查将失败。考虑以下代码:
auto child = parent->getFirstChild();
if ( parent == child->getParent() ) // Will be false, as they point to different
// instantiations of Parent.
...
if ( child->getParent() == child->getParent() ) // False for the same reason.
...
auto sibling = child->getNextChild();
if ( parent == sibling->getParent() ) // Also false for the same reason.
...
此外,当使用std::shared_ptr
时,可以考虑使用std::make_shared
来减少分配时出现的一些开销。
- 1d 智能指针不适用于语法 (*)++
- 优先顺序:智能指针和类析构函数
- 对于C++中使用智能指针的指针算术限制,有没有一种变通方法
- 智能指针作为无序映射键,并通过引用进行比较
- 智能指针概念所有权和寿命
- 正在理解智能指针,但出现错误:未分配正在释放的指针
- 尝试使用智能指针时引发异常
- 我可以制作指向智能指针的智能指针吗?
- 通过智能指针和转换对基本模板参数进行模板推导
- OpenCV 我应该使用智能指针来防止内存泄漏吗?
- 从堆栈分配的原始指针构造智能指针
- 初始化指向类实例的智能指针并访问其方法
- 如何使用 std::make_shared 创建基类类型的智能指针?
- 给定一个指向堆分配内存的指针,智能指针实现如何为其找到合适的释放函数?
- 编译器不会使用 -std=c++11 编译智能指针
- 具有智能指针的多态性
- C++:矢量分配器行为、内存分配和智能指针
- 在什么情况下,需要共享智能指针而无法使用唯一指针?
- 指向函数签名中的常量智能指针
- 使用智能指针附加的继承对象的深层复制