不一致的所有权

3

我有一个类,到目前为止它一直持有另一个类的引用,因为它不拥有该类并且不负责管理它的内存。

class MyClass
{
    OtherClass& m_other;
public:
    MyClass( OtherClass& other ) : m_other( other ) {}
};

然而,在某些情况下,MyClassm_other 的所有者,我希望删除MyClass 时也会删除 OtherClass。但在某些情况下,它不是所有者。

在这种情况下,更合适的是使用两个类来表示这两种情况,还是使用一个封装了这两种情况(使用 unique_ptr)的单个类呢?例如:

class MyClassRef
{
    OtherClass& m_other;
public
    MyClassRef( OtherClass& other ) : m_other( other ) {}
};

class MyClassOwner
{
    std::unique_ptr<OtherClass> m_other; // Never null
public:
    MyClassOwner( std::unique_ptr<OtherClass> other ) : m_other( std::move( other ) ) {}
};

vs

class MyClass
{
    OtherClass& m_other; // class may or may not be the one we manage.
    std::unique_ptr<OtherClass> m_managed; // May be null
public:
    MyClass( std::unique_ptr<OtherClass> managed ) : m_other( *managed ), m_managed( std::move( m_managed ) ) {}
    MyClass( OtherClass& other ) : m_other( other ), m_managed() {}
};

这可能是一个比较简单的例子,但通常在处理分割情况时,是创建新类来处理这些情况更好呢,还是将尽可能多的情况封装在一个类中 - 到合理的程度。

编辑:第三个选项与第二个选项类似,即使用std::shared_ptr<T>,例如:

class MyClass
{
    std::shared_ptr<OtherClass> m_other;
public:
    MyClass( std::shared_ptr<OtherClass> other) : m_other( other ) {}
    MyClass( OtherClass& other ) : m_other( std::shared_ptr<OtherClass>( &other, []( OtherClass* p ){} ) ) {}
};

请注意,我希望 MyClass 仍然接受引用,以允许指向栈分配对象的指针;这就是为什么构造函数创建了一个具有自定义删除器的 shared_ptr<OtherClass>,而不是删除栈对象。

1
如果您选择分割类选项,那么您必须创建大量的重载功能来处理两种类型。 - Some programmer dude
第四个选项:仔细检查你的设计。由于提供的细节不足以帮助我们,但这是一个相当不寻常的设计,因此值得检查它是否是一个好的设计。 - Andriy Tylychko
1个回答

4

在某些情况下,类可能是所有者,而在其他情况下它不是所有者。这时候您应该使用std::shared_ptr<T>代替std::unique_ptr<T>,后者要求资源具有唯一的所有权,前者则维护使用计数

只要通过std::shared_ptr<T>智能指针保留了对m_other所指向对象的所有引用,无论程序的哪个部分拥有该对象,资源管理都将自动完成。


我不确定这个答案是否令人满意。就我所理解的std::shared_ptr<T>的语义而言,我(MyClass)是这个对象的明确拥有者 - 但也可能有其他人拥有它。我要定义的是一种情况,我可能拥有或可能不拥有这个对象。特别是在我的情况下,我引用的对象是一个堆栈分配的对象,不能很好地与智能指针配合使用 - 我知道可以使用自定义删除器来不删除对象,但这似乎容易出错。 - jakedipity
1
@JacobHull 在这种情况下,您不能使用共享指针,因为它们无法与堆栈对象一起使用。这里至少有两种方法:(1)切换到不使用堆栈对象:性能差异应该太小而无法测量,而自动化资源管理将使您可以自动处理所有权,或者(2)编写自己的所有权管理代码-将指针和一个“bool”传递给构造函数,指示是否拥有依赖项,并在析构函数中删除拥有的对象。 - Sergey Kalinichenko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接