【问题标题】:C++ - when should I use a pointer member in a classC++ - 我什么时候应该在类中使用指针成员
【发布时间】:2010-11-13 14:56:42
【问题描述】:

在学习 C++(和 Direct3D,但那是前段时间)时让我感到困惑的一件事是何时应该在类中使用指针成员。例如,我可以使用非指针声明:

private:
    SomeClass instance_;

或者我可以使用指针声明

private:
   Someclass * instance_

然后在构造函数中对其使用 new() 。

我知道,如果 SomeClass 可以从另一个类、COM 对象或 ABC 派生,那么它应该是一个指针。还有其他我应该注意的准则吗?

【问题讨论】:

    标签: c++ pointers


    【解决方案1】:

    指针有以下优点:

    a) 您可以进行延迟初始化,这意味着仅在第一次真正使用之前初始化/创建对象。

    b) 设计:如果您对外部类类型的成员使用指针,您可以在您的类上方放置一个前向声明,因此不需要在您的标头中包含该类型的标头 - 而不是您在您的 .cpp 中包含第三方头文件 - 这样做的好处是可以减少编译时间并通过包含太多其他头文件来防止副作用。

    class ExtCamera;  // forward declaration to external class type in "ExtCamera.h"
    
    class MyCamera {
    public: 
      MyCamera() : m_pCamera(0) { }
    
      void init(const ExtCamera &cam);
    
    private:
       ExtCamera  *m_pCamera;   // do not use it in inline code inside header!
    };
    

    c) 可以随时删除指针 - 因此您可以更好地控制生存时间并可以重新创建对象 - 例如在失败的情况下。

    【讨论】:

    • 对于延迟初始化,我建议尽可能使用boost::optional。它比指针更安全,因为你不能对其进行算术运算。
    • 但是很多人(像我一样)不使用 Boost - 所以这是一种非常独立于平台和框架的方式 ;-) ...例如我只使用 Qt :-)
    • 但是那些不使用boost的应该:)
    • @Extrakun,确保您没有尝试在该头文件中的任何位置访问 QPoint 的任何成员。
    • 您仍然可以将前向声明与引用一起使用-只要您的标头中没有任何代码使用(访问)引用-因此任何声明都有效,但不是内联代码。
    【解决方案2】:

    3DH 概述了使用指针的优点:延迟初始化、减少标头依赖性以及控制对象的生命周期。

    这也是缺点。当您有一个指针数据成员时,您可能必须编写自己的复制构造函数和赋值运算符,以确保正确创建对象的副本。当然,你也必须记得在析构函数中删除对象。此外,如果将指针数据成员添加到现有类,则必须记住更新复制构造函数和 operator=。简而言之,拥有一个指针数据成员对你来说更有用。

    另一个缺点实际上是控制指针指向的对象的生命周期的另一面。当对象被销毁时,非指针数据成员会自动销毁,这意味着只要对象存在,您就可以始终确保它们存在。使用指针,您必须检查它是否为nullptr,这也意味着您必须确保将其设置为nullptr,只要它不指向任何东西。必须处理所有这些可能很容易导致错误。

    最后,访问非指针成员可能会更快,因为它们在内存中是连续的。另一方面,访问指向在堆上分配的对象的指针数据成员可能会导致缓存未命中,从而使其变慢。

    您的问题没有单一的答案。您必须查看您的设计,并确定指针数据成员的优势是否超过了额外的麻烦。如果减少编译时间和头文件依赖性很重要,请使用pimpl idiom。如果在某些情况下您的对象可能不需要您的数据成员,请使用指针,并在需要时分配它。如果这些听起来不像是令人信服的理由,并且您不想做额外的工作,那么不要使用指针。

    如果延迟初始化和减少标头依赖关系很重要,那么您应该首先考虑使用智能指针,如std::unique_ptrstd::shared_ptr,而不是原始指针。智能指针使您免于使用上述原始指针的许多麻烦。

    当然,还有一些注意事项。 std::unique_ptr 会自行清理,因此您无需添加或修改类的析构函数。但是,它是不可复制的,因此将唯一指针作为数据成员会使您的类也不可复制。

    使用std::shared_ptr,您不必担心析构函数或复制或赋值。但是,共享指针会导致引用计数的性能损失。

    【讨论】:

      【解决方案3】:

      如果可以的话,将它分配到堆栈上,如果必须的话,从免费存储中分配。这里有一个similar question,在这里你可以找到所有的“为什么”。

      你在游戏和其他东西上看到大量使用指针的原因是因为 DirectX 是一个 COM 接口,老实说,过去的大多数游戏程序员都不是真正的 C++ 程序员,他们是 C-with -classes 程序员,并且在 C 中指针的用法很常见。

      【讨论】:

        【解决方案4】:

        使用指针的另一个原因是动态绑定。如果你有一个带有虚方法的基类和一些派生类,你只能使用指针获取动态绑定。

        【讨论】:

        • 这不太对 - 您可以与引用进行动态绑定。
        • @boxofrats True,但您不能重新绑定引用。所以如果你需要动态绑定和重新绑定,那么指针似乎是唯一的方法。
        猜你喜欢
        • 2019-02-27
        • 2010-11-02
        • 2011-10-04
        • 2015-10-31
        • 2010-12-30
        • 1970-01-01
        • 2010-09-11
        相关资源
        最近更新 更多