从C ++类返回shared_ptr

时间:2018-08-16 12:09:46

标签: c++

我有一个问题与从类返回共享指针有关。 我班的一部分看起来像这样:

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

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

其中m_derivedInterfacem_spBase都是我班的私人成员,即:

private:

   IBaseInterfaceSP m_spBase ;

   DerivedInterface m_derivedInterface;

此外,DerivedInterface继承自IBaseInterfaceSP

getInterface是我班的公共职能。

这是从类中返回指针的正确方法吗?切片或类似的东西会有问题吗?

P.S。如果有一些不清楚的地方,我很抱歉(不允许我在此处公开所有代码,仅发布某些部分),如果是这样,请告诉我。

1 个答案:

答案 0 :(得分:4)

我看到这段代码有几个问题。

1。延迟初始化

每次调用getInterface时,都会创建IBaseInterface类的新实例。作为您班级的用户,我不会从名为“ get”的方法获得这种行为。

我猜您想实现延迟初始化,在这种情况下,您可以这样做:

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

2。命名约定

您正在实例化一个名为IBaseInterface的类,这听起来像一个抽象类(“ I”前缀在历史上一直用于接口)。您可能应该重命名您的类,以使其听起来不抽象。另外,“ I”前缀在“ Interface”后缀中是多余的。

但是,在我认为“好的” OOP中,用户不需要知道您正在向他们提供接口。因此,不需要将具体名称与抽象类区分开的命名约定。

3。所有权语义

共享指针用于共享所有权:返回共享指针时,您是在告诉类的用户他们也将拥有返回的对象。通常,不需要。在大多数情况下,您会返回一个非所有者指针,也就是原始指针。例如:

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

4。切片

这里确实有切片发生。这行:

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

实际上扩展为包含与此等效的代码:

auto newInstance = new IBaseInterface(m_derivedInterface );

依次,上面的行将调用IBaseInterface类的副本构造函数,其签名类似于:

IBaseInterface(IBaseInterface& other)

因此,在该调用的上下文中,m_derivedInterface被解释为IBaseInterface引用。因此,在调用“ new”期间,仅IBaseInterface的成员将被复制,从而丢失存储在派生类DerivedInterface中的所有信息。


所有这些,在我看来,您真正想要的是直接访问m_derivedInterface对象。您现在正在做的是,将实例复制到另一个对象中并返回新对象。我认为您真正想要的是:

IBaseInterface* getInterface()
{
    return &m_derivedInterface;
}

如果您坚持使用共享所有权,只需存储指向m_derivedInterface的共享指针而不是值:

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

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

std::shared_ptr<IBaseInterface> m_derivedInterface;