OOP中如何正确使用智能指针

How to correctly use smart pointers in OOP

我想知道在面向对象编程中使用 std::unique_ptr 的正确方法是什么。假设我有一个 class 包含一个必须可以通过指针传递的成员对象

class B
{/*Some code here*/};

class A
{
public:
    A();
    B* getMember();
private:
    std::unique_ptr<B> member
};

首先:成员应该是 std::unique_ptr 还是 std::shared_ptr 以避免内存泄漏?

其次,如果我想要

,我的getter的实现是什么
  1. 允许修改成员?
  2. 不允许修改成员?

我最初做了:

B* A::getMember()
{
    return member.get();
}

但我正在考虑让成员成为 std::shared_ptr 并调整 getter:

class A
{
public:
    A();
    std::shared_ptr getMember();
private:
    std::shared_ptr<B> member
};

std::shared_ptr A::getMember()
{
    return member;
}

最广泛接受的标准实施是什么?

如果您分发指向 unique_ptr 的指针,那么您并没有真正将其视为“唯一”。

您真正需要的是shared_ptr。你的第二种方法是正确的方法。这些旨在根据需要进行复制并保留引用计数。这意味着只要您持有 shared_ptr 对象的副本,就可以访问它。

在前一种情况下,您完全不知道您的指针在收到后是否仍然有效。您必须手动跟踪它,这有点违背了使用智能指针的意义。

shared_ptr 意味着一个复杂的所有权规则,其中所讨论的对象由多个同等的当事方拥有,并且其生命周期不容易确定。决定使用 shared_ptr 因为它更简单或更容易,就像使用火箭筒杀死果蝇一样打扰你,因为它比苍蝇拍更强大。

在 C++ 中,没有避免考虑所有权的简单方法。

unique_ptr 提供了一个简单的所有者关系来管理生命周期。值类型(或具有值语义的类型)提供更简单的生命周期管理。没有人会对新手 int x=7; 的一生感到困惑。

C++可以支持运行时多态值类型;参见 std::function。如有疑问,请使用值。

class A {
public:
  A();
  B b;
};

更容易思考。

现在,如果您正在做类似 UI 框架的事情,那么您的 UI 元素将归您的框架所有。您可能需要一个命名系统、ASL 中的配置文件,以及一种将您的 UI 连接到操作并使用代码修改您的 UI 的方法。

在 none 旁边将涉及一个 class,其成员子对象通过访问器返回指向它的指针。

也许您的 UI 是写入共享 ptr 数据的不可变副本,您可以 get/setfrom 框架。在这里,不可变数据是真正共享的;它就像一个整数。

无论如何,无论何时共享 B 指针,无论是哑的、唯一的、共享的、不可变的还是写时复制,B 与 A 分开存在意味着什么。要么 B 成为 A 状态某些部分的接口,在这种情况下它的生命周期在逻辑上是相关的,要么它独立存在,在这种情况下你可能需要值语义。

做出那个决定后,共享指针可能是错误的生命周期规则。如果它是 A 状态的一部分的接口,它比共享所有权所暗示的 A 长寿是一个错误,如果它是一个值,你 set/get,获取它并修改状态隐式地充当 A 状态的接口!连A都不知道!

A 正在从 B 发送状态更改通知? Bring 能否获取提供状态变化通知的B?懂事;在这里,B 可以是 UI 主题颜色,A 可以是控件。但是这里 A 可能有一个指向 const 主题颜色集的共享 ptr 以及一个指向主题更改消息的订阅令牌。 (这里的颜色集是合法共享的)

简而言之,默认共享指针是不好的。当您不能使用值时,请使用 unique ptr。所有权遵循生命周期,生命周期遵循语义。默认为值,C++ 是为数不多的具有真正可靠值支持的 OO 语言之一。