代码之家  ›  专栏  ›  技术社区  ›  foraidt

始终存在的动态分配成员的指针或引用?

  •  2
  • foraidt  · 技术社区  · 16 年前

    CContainer 那有一些成员 CMemberX CMemberY ,它们相互独立,相互独立 CClientA , CClientB 使用 容器

    #include "MemberX.h"
    #include "MemberY.h"
    
    class CContainer
    {
    public:
        CMemberX & GetX() const { return m_x; }
        CMemberY & GetY() const { return m_y; }
    
    private:
        CMemberX m_x;
        CMemberY m_y;
    };
    

    我想避免重新编译所有文件 CClient 在修改其中一个 CMember m_x m_y .

    最初,我向成员们指出:

    // Container.h
    class CMemberX;
    class CMemberY;
    
    class CContainer
    {
    public:
        CContainer();
        ~CContainer();
    
        CMemberX & GetX() const { ASSERT(m_pX != NULL); return *m_pX; }
        CMemberY & GetY() const { ASSERT(m_pY != NULL); return *m_pY; }
    
    private:
        CMemberX* m_pX;
        CMemberY* m_pY;
    };
    
    // Container.cpp
    #include "Container.h"
    #include "MemberX.h"
    #include "MemberY.h"
    
    // Allocate members on heap
    CContainer::CContainer() : m_pX(new CMemberX()), m_pY(new CMemberY()) {}
    CContainer::~CContainer() { delete m_pX; delete m_pY; }
    

    然后我想,我也可以使用引用而不是指针,因此它看起来更像原始代码:

    // Container.h
    class CMemberX;
    class CMemberY;
    
    class CContainer
    {
    public:
        CContainer();
        ~CContainer();
    
        CMemberX & GetX() const { return m_x; }
        CMemberY & GetY() const { return m_y; }
    
    private:
        CMemberX & m_x;
        CMemberY & m_y;
    };
    
    // Container.cpp
    #include "Container.h"
    #include "MemberX.h"
    #include "MemberY.h"
    
    // Allocate members on heap
    CContainer::CContainer() : m_x(*new CMemberX()), m_y(*new CMemberY()) {}
    CContainer::~CContainer() { delete &m_x; delete &m_y; }
    

    我不喜欢指针成员的地方在于 就像指针一样 NULL

    哪种方法更可取?有更好的解决办法吗?

    实例 容器 在任何情况下,类都不会相互复制或分配。

    7 回复  |  直到 16 年前
        1
  •  5
  •   user3458 user3458    16 年前

    我认为这就是常量变量的作用:

    CMember * const m_x;
    

        2
  •  4
  •   Steve Jessop    16 年前

    我认为在有所有权语义的情况下使用引用有点奇怪。不 必要地 从各方面考虑,让它成为一个坏主意,但它确实对你不利。

    我想我只在以下两种情况下使用引用作为成员:

    因此,例如,工厂或服务对象之类的注入依赖项可能是合适的。与此相反,在C++中,您通常更喜欢用模板参数而不是对象注入依赖关系,因此问题不会出现。

    我还发现,我使用C++的时间越长,我就越希望类型可以被分配,除非有一个很好的原因。以您想要的方式减少编译时依赖性的常用技巧是“Pimpl”,而不是“Rimpl”,这是有原因的。通过从一个对象成员切换到一个引用成员,您使您的类成为非默认可复制类,而以前它可能是可复制的。这个实现细节不应该约束类的接口。使用Pimpl,您可以干净地实现赋值和交换。使用这些引用,您必须分配或交换两个成员。如果第二次交换失败,您就失去了强大的异常保证:尽管如果您的CMemberX和CMemberY类没有失败赋值和交换,这并不重要。

        3
  •  2
  •   Community Mohan Dere    9 年前

    Should I prefer pointers or references in member data? )在我看来,大多数人的意见(碰巧也是我的)是——不要。如果您不想更改指针,请将它们设置为常量-我不知道,在给定代码的情况下,它们如何可能为NULL。

        4
  •  1
  •   emvee    16 年前

    使用前向声明时,唯一允许使用的是声明指向前向声明类型的指针。

    简言之:要么您永远不必重新编译[您只是声明指向前向声明类型的指针],要么您总是必须重新编译,以防您实际使用CContainer。

        5
  •  1
  •   James Hopkin    16 年前

    史蒂夫·杰索普(Steve Jessop)已经顺便提到了pImpl成语,但我认为如果你还没有遇到它,你应该检查一下: Compilation Firewalls

        6
  •  0
  •   quamrana Ryuzaki L    16 年前

    此外,还可以声明指针常量: CMember* const m_pX; 表示在初始化后不能更改。现在,编译器将捕获意外更改。

        7
  •  0
  •   Loki Astari    16 年前

    你并不是在给自己买东西。
    (在有限的情况下,编译时间略短)。

    但是您正在堆积大量需要维护的其他代码。

    如果这些对象是自然成员,则将其保留为成员。

    • 复制构造对象时会发生什么。

      • 使用指针或引用,您必须做额外的工作来复制已经提供的功能。
    • 指定对象时会发生什么情况。
      • 引用将不起作用(尽管您可以通过使用boost引用来解决这个问题)。
        但您仍然存在希望复制成员的问题。

      • 否则,您需要开始考虑共享指针来实现所需的功能。

    目前,版本2和版本3(问题代码)存在严重缺陷,唯一有效的版本是版本1。

    在我看来,一个简单的事实是,版本1的维护成本将大大降低,因此推荐版本2或版本3都会适得其反。与您添加到代码中的复杂性相比,当成员发生更改时,编译一个以上类所需的额外时间相对较小。

    另外,您在其他人的评论中提到,代码没有上面描述的那么干净。这只是强调了我的观点,这是一个糟糕的优化,它将使类很难正常工作并保持在该状态。