所有权不一致
Inconsistent Ownership
我有一个 class,直到此时它引用了另一个 class,因为它不拥有那个 class 并且不负责管理它的内存。
class MyClass
{
OtherClass& m_other;
public:
MyClass( OtherClass& other ) : m_other( other ) {}
};
然而,在某些情况下,MyClass
是 m_other 的所有者,我希望删除导致删除 OtherClass
。在某些情况下,它不是所有者。
在这种情况下,用两个 class 表示两种情况更合适,还是用一个 class 封装两种情况(使用 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 ) ) {}
};
对
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() {}
};
这可能是一个相当简单的示例,但一般来说,在处理拆分案例时,最好是创建新的 classes 来处理这些案例……还是将尽可能多的案例封装在一个 class - 达到合理水平。
编辑:与第二个选项类似的第三个选项是使用 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>
不删除堆栈对象的原因。
当 class 在某些情况下可能是所有者,而在其他一些情况下它不是所有者时,您应该使用 std::shared_ptr<T>
,这会维护 use count,代替 std::unique_ptr<T>
,这需要资源的唯一所有权。
只要 m_other
指向的对象的所有引用都通过 std::shared_ptr<T>
智能指针维护,资源管理将为您自动完成,而不管拥有该对象的程序部分如何对象。
我有一个 class,直到此时它引用了另一个 class,因为它不拥有那个 class 并且不负责管理它的内存。
class MyClass
{
OtherClass& m_other;
public:
MyClass( OtherClass& other ) : m_other( other ) {}
};
然而,在某些情况下,MyClass
是 m_other 的所有者,我希望删除导致删除 OtherClass
。在某些情况下,它不是所有者。
在这种情况下,用两个 class 表示两种情况更合适,还是用一个 class 封装两种情况(使用 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 ) ) {}
};
对
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() {}
};
这可能是一个相当简单的示例,但一般来说,在处理拆分案例时,最好是创建新的 classes 来处理这些案例……还是将尽可能多的案例封装在一个 class - 达到合理水平。
编辑:与第二个选项类似的第三个选项是使用 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>
不删除堆栈对象的原因。
当 class 在某些情况下可能是所有者,而在其他一些情况下它不是所有者时,您应该使用 std::shared_ptr<T>
,这会维护 use count,代替 std::unique_ptr<T>
,这需要资源的唯一所有权。
只要 m_other
指向的对象的所有引用都通过 std::shared_ptr<T>
智能指针维护,资源管理将为您自动完成,而不管拥有该对象的程序部分如何对象。