如何在关联指针时编写无错误的代码

How to write a bug-free code when a pointer is associated?

本文关键字:无错误 代码 关联 指针      更新时间:2023-10-16

例如

struct A
{
    void foo() {};
};
struct B
{
    B() {}
    void setA(A* a) { mA = a; }
    foo()           { mA->foo(); }
    A *mA;
};

B中有一个关联的A(只是一个地址)。B::mA绝不能null.我通常忘记setA并引入错误。有什么好的做法可以避免它?下面setA怎么样?

void B::setA(A& a) { mA = &a; }

最好的方法是首先避免使用指针。如果必须使用指针,请考虑使用智能指针,例如 std::unique_ptrstd::shared_ptr 。并且始终始终初始化指针,要么为 null(除非您使用智能指针)或已分配的内容。并且始终在使用它们之前始终检查空值。

首先,也是最重要的事情,是永远不要留下指针初始 化。 至少,将其设置为 nullptr(或NULLpre-C++11) 在构造函数中,因此您至少可以测试它的有效性后。

除此之外,很大程度上取决于它应该指向什么:

  • 如果它所指向的内容的生命周期保证会超过对象的生存期(在两个方向上:它存在于您的之前对象已构造,并且在对象被构造后将继续存在析构),将其作为对构造函数的引用传递,并获取用于初始化指针的引用的地址。

  • 如果它所指向的内容的生命周期可能要到您的之后才能开始对象是构造的,则必须在构造函数,在 setA 函数中分配给它,并验证它是否为不是每次要使用它时都为空。

  • 如果它所指向的内容的生存期可能会在您的对象之前结束破坏了,那么你需要观察者模式的某种变体,通知您的对象指向的对象已被破坏,并将指针设置为 null。 在这种情况下,您还必须检查每次使用前都为空。 过去,我使用过ManagedPtr为此,但这不是一个通用的解决方案。 (它将使指针清空,但是如果指针在地图或其他东西中,这通常是在这种情况下,它不会从地图中删除该条目。

  • 如果对象的生存期应影响指向对象,那么您应该考虑使用 std::shared_ptr .我发现这种情况在实际代码中非常罕见,但它们确实会发生。(请注意,如果您确实使用std::shared_ptr,则必须非常非常小心。 您只能从任何给定构造一个std::shared_ptr原始指针不会遇到问题。 在我们自己的代码库中,我们已经禁止std::shared_ptr,并使用我们自己的侵入性参考计数指针,以避免此类问题。 std::shared_ptr精心设计,以最大限度地提高悬空指针的风险和多次删除同一对象。

如果对象总是在对象之前初始化B则使用引用作为首选:

struct B
{
    B(A& a) : mA(a) {}    
    foo() { mA.foo(); }    
    A& mA;
};
A a;
B b(a);   

"我通常忘记设置A,并且引入了错误。

所以强迫自己通过构造函数来设置它:

struct B
{
    public:
      B(A *a) : ma(a) {}
    private:    
      A *mA;
};

让我们foo检查一下:

foo()
{
  if (mA)
    mA->foo();
  else
    // handle it, throw exception, ignore, ...!
}