3

我正在处理一个由多种不同类型(属性、父级、子级等)组成的模型。每种类型都与来自 ac 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;
};

然后我通过类属性、父类和子类实现这些接口。

因此 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,这会改变接口和我的很多代码......

4

3 回答 3

2

返回 a 没有任何问题shared_ptr,但我会尽力说服您这可能不是最佳选择。

通过使用智能指针,您可以获得安全优势,但您的 API 用户失去了使用最适合他们需要的智能指针类型的灵活性,而必须始终使用shared_ptr.

这还取决于您对安全性的重视程度高于灵活性,但我个人会考虑返回一个裸指针并允许用户使用他想要的智能指针。当然,如果shared_ptr出于某种原因需要我使用,我会的。

于 2012-08-06T12:39:52.693 回答
2

关键问题是:返回指针的语义是什么?

  • 如果返回的父/子/属性对象的生命周期独立于返回的(可能在某种意义上,拥有)对象,则返回是合理的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错误地建议所有权转移
    • 原始指针没有明确做出任何误导性的承诺,但也没有给出关于正确使用的任何提示

因此,如果调用者只是获得对对象内部状态的工作引用,而没有所有权转移或对象生命周期的延长,则不建议使用任何智能指针。

考虑只返回一个参考。

于 2012-08-06T13:03:39.170 回答
0

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来减少分配时发生的一些开销。

于 2012-08-06T13:09:10.413 回答