Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Which smart pointer should I use?

Tags:

c++

I'm woring against a model which consists of a number of different types (Properties, Parent, Child, etc). Each type is associated with a set of functions from a c api. For example:

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);

I have in turn created a set of C++ interfaces for this c api library, as follows:

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;
};

I then implement these interfaces via the classes Properties, Parent and Child.

So a Child instance will take its specific ChildHandle via its constructor and its getParent function will look something like this:

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)));
}

Is it reasonable for me to return a shared_ptr here in your opinion. I cant use std::unique_ptr since Google Mock requires parameters and return values of mocked methods to be copyable. I'm mocking these interfaces in my tests via Google Mock.

I'm thinking also about how things might get optimized in the future which might present the possibly of circular references. This could be caused if caching is used to avoid multiple calls to the C api (for example, no need for a child to establish its parent more than once) combined with say the Child constructor taking its Parent. This would then require the use of weak_ptrs which would change the interfaces and a lot of my code...

like image 789
Baz Avatar asked Sep 10 '26 19:09

Baz


1 Answers

The key question is: what are the semantics of the returned pointer?

  • if the returned parent/child/properties object has a lifetime independent of the returning (presumably, in some sense, owning) object, it's reasonable to return shared_ptr: this indicates that the caller and callee have equal rights to decide the object's lifetime

    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?
    
  • if the returned object has a lifetime dependent on the callee's own lifetime, then:

    • shared_ptr will wrongly suggest it's meaningful for the caller to extend the returned object's lifetime beyond that of the callee
    • unique_ptr will wrongly suggest transfer of ownership
    • raw pointer doesn't explicitly make any misleading promises, but doesn't give any hint about correct use either

So, if the caller is just getting a working reference to your object's internal state, without either transfer of ownership or extension of object lifetime, it doesn't suggest using any smart pointer.

Consider just returning a reference.

like image 118
Useless Avatar answered Sep 13 '26 09:09

Useless



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!