0

例如

struct A
{
    void foo() {};
};

struct B
{
    B() {}

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

    A *mA;
};

内有一个A关联的(只是一个地址)B。而且B::mA绝不能null。我通常会忘记setA并引入错误。有什么好的做法可以避免呢?那么setA如下呢?

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

4 回答 4

6

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

于 2013-09-21T12:16:39.517 回答
3

首先,也是最重要的事情是永远不要让指针处于未初始化状态。至少,在构造函数中将其设置为nullptr(或NULL在 C++11 之前的版本中),这样您至少可以稍后测试它的有效性。

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

  • 如果它所指向的对象的生命周期保证超过你的对象的生命周期(在两个方向上:它在你的对象被构​​造之前就存在,并且在你的对象被破坏之后将继续存在),将它作为引用传递给构造函数,并获取引用的地址来初始化指针。

  • 如果它所指向的对象的生命周期可能直到你的对象被构​​造之后才开始,那么你必须在构造函数中将指针设置为 null,在函数中分配给它setA,并在每次要使用时验证它不为 null它。

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

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

于 2013-09-21T12:59:36.840 回答
1

“我通常会忘记 setA 并引入错误。”

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

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

    private:    
      A *mA;
};

让我们foo检查一下:

foo()
{
  if (mA)
    mA->foo();
  else
    // handle it, throw exception, ignore, ...!
}
于 2013-09-21T12:21:38.417 回答
1

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

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

A a;
B b(a);   
于 2013-09-21T12:22:42.507 回答