简体   繁体   中英

Return a shared_ptr from a class C++

I have a question which has to do with returning a shared pointer from a class. Part of my class looks like this:

typedef std::shared_ptr<IBaseInterface> IBaseInterfaceSP;
...

IBaseInterfaceSP getMyInterface()
   {
      m_spBase = std::make_shared<IBaseInterfaceSP>( m_derivedInterface);
      return m_spBase;
   }

where both m_derivedInterface and m_spBase are private members of my class, ie:

private:

   IBaseInterfaceSP m_spBase ;

   DerivedInterface m_derivedInterface;

Also, DerivedInterface inherits from IBaseInterfaceSP .

getInterface is a public function of my class.

Is this the right way to return a pointer from my class? Will there be any problems with slicing or anything similar?

PS I am sorry if something is unclear ( I am not allowed to post all the code here in public, only some parts), if so, just let me know.

I can see several problems with this code.

1. Lazy initialization

Each time you call getInterface, you create a new instance of your IBaseInterface class. As a user of your class, I would not expect this behavior from a method called "get".

I guess you wanted to implement lazy initialization, in which case you would do it like this:

IBaseInterfaceSP getInterface()
{
    if (!m_spBase)
    {
        m_spBase= std::make_shared<IBaseInterface>( m_derivedInterface );
    }
    return m_spBase;
}

2. Naming conventions

You are instantiating a class called IBaseInterface, which sounds like an abstract class (the "I" prefix was historically used for interfaces). You should probably rename your class so that it doesn't sound abstract. Also, the "I" prefix is redundant with the "Interface" suffix.

However, in what I consider "good" OOP, users do not need to know that you are handing them an interface. There is thus no need for a naming convention that differentiates concrete from abstract classes.

3. Ownership semantics

Shared pointers are meant for shared ownership : when you return a shared pointer, you are telling the users of your class that they will own the returned object, too. Usually, that is not needed. In most cases you would return a non-owning pointer, aka raw pointer. For example:

IBaseInterface* getInterface()
{
    return m_spBase.get(); // Instantiation done elsewhere, for example in constructor
}

4. Slicing

There is indeed slicing happening here. This line:

m_spBase = std::make_shared<IBaseInterface>( m_derivedInterface );

Actually expands to code that contains something equivalent to this:

auto newInstance = new IBaseInterface(m_derivedInterface );

In turn, the line above will call the copy constructor of the IBaseInterface class, whose signature is similar to:

IBaseInterface(IBaseInterface& other)

Thus, m_derivedInterface is interpreted as an IBaseInterface reference in the context of that call. Only the members of IBaseInterface will thus be copied during the call to "new", thereby losing all the information stored in the derived class, DerivedInterface.


All that said, it seems to me that what you really want is direct access to the m_derivedInterface object. What you are doing right now is, you copy the instance into another object and return the new object. I think what you really want is this:

IBaseInterface* getInterface()
{
    return &m_derivedInterface;
}

If you insist on using shared ownership, just store a shared pointer to m_derivedInterface instead of a value:

MyClass(Args args)
{
    m_derivedInterface.reset(new DerivedInterface(args));
}

std::shared_ptr<IBaseInterface> getInterface()
{
    return m_derivedInterface;
}

std::shared_ptr<IBaseInterface> m_derivedInterface;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM