Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/jenkins/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 对成员类/对象变量使用指针更好吗?_C++_Pimpl Idiom - Fatal编程技术网

C++ 对成员类/对象变量使用指针更好吗?

C++ 对成员类/对象变量使用指针更好吗?,c++,pimpl-idiom,C++,Pimpl Idiom,当我试图保持一个关于include的干净头文件时,我发现我可以做得更好,让我的所有成员指向需要包含其他头文件的类/对象,因为这样我可以使用前向声明而不是include 但我开始怀疑这是否是一个好的经验法则 以下面的类为例-选项1: class QAudioDeviceInfo; class QAudioInput; class QIODevice; class QAudioRx { public: QAudioRx(); private: QAudioDeviceInfo

当我试图保持一个关于include的干净头文件时,我发现我可以做得更好,让我的所有成员指向需要包含其他头文件的类/对象,因为这样我可以使用前向声明而不是include

但我开始怀疑这是否是一个好的经验法则

以下面的类为例-选项1:

class QAudioDeviceInfo;
class QAudioInput;
class QIODevice;

class QAudioRx
{
public:
    QAudioRx();
private:  
    QAudioDeviceInfo *mp_audioDeviceInfo;
    QAudioInput *mp_audioInput;
    QIODevice *mp_inputDevice;
};
但是,可以这样重新编写-选项2:

#include "QAudioDeviceInfo.h"
#include "QAudioInput.h"
#include "QIODevice.h"

class QAudioRx
{
public:
    QAudioRx();
private:  
    QAudioDeviceInfo m_audioDeviceInfo;
    QAudioInput m_audioInput;
    QIODevice m_inputDevice;
};
选项1通常是我的首选,因为它是一个更好的更干净的标题。然而,备选方案2不要求动态分配/取消分配资源

也许这可以被视为一个主观/基于意见的问题,我知道舆论警察会对此负责,所以让我们避免我喜欢、我更喜欢并坚持事实/关键点

所以我的问题是,总的来说,如果有最佳实践,什么是最佳实践?为什么?或者,如果通常没有一种最佳实践,那么何时使用每一种最佳实践是好的

编辑


抱歉,这实际上是针对私有变量的,而不是公共变量。

如果需要指针,请使用指针。指针不是用来避免包含的。包罗万象并非邪恶。当你需要使用它们时,就使用它们。简单规则等于快乐编程


在您的案例中使用指针会带来很多不必要的开销。您可能需要动态地分配对象,这对于您的情况来说不是一个好的选择。您还必须手动处理内存管理。简单地说,这里没有理由使用指针,除非您的案例要求,例如,您希望对象比指针本身活得更久,例如非所有权模式。

如果需要指针,请使用指针。指针不是用来避免包含的。包罗万象并非邪恶。当你需要使用它们时,就使用它们。简单规则等于快乐编程


在您的案例中使用指针会带来很多不必要的开销。您可能需要动态地分配对象,这对于您的情况来说不是一个好的选择。您还必须手动处理内存管理。简单地说,没有理由在这里使用指针,除非您的案例要求,例如,您希望对象比指针本身更有效,例如非所有权模式。

当您在处理类数很少的小项目时,您应该使用选项2

但当您处理的是一个非常大的项目,其中类的数量非常大,并且项目的编译时间是开发项目体系结构的标准之一时,请选择选项1


在大多数情况下,选项1很好。在实际应用程序中,您需要将这两个选项结合起来,在编译时间和代码的美观性之间进行权衡,而不使用指针和对象的新动态分配。

当您处理类数很少的小项目时,您应该使用选项2

但当您处理的是一个非常大的项目,其中类的数量非常大,并且项目的编译时间是开发项目体系结构的标准之一时,请选择选项1


在大多数情况下,选项1很好。在实际应用程序中,您需要将这两个选项结合起来,在编译时间和代码的漂亮外观之间进行权衡,而无需指针和对象的新动态分配。

编译时间和编译时间相关性之间存在权衡,这通常与所需的包含文件数量和简单高效

选项1的编译速度更快,但几乎可以肯定运行速度较慢。每次访问成员变量时,都有一个通过指针的间接寻址,指针引用的对象必须单独分配和管理。如果分配是动态的,那么会有额外的成本,管理单独对象的额外逻辑有引入bug的风险。首先,您有原始指针,所以您必须定义或删除复制构造函数、复制赋值,可能还有析构函数,可能还有移动构造函数和移动赋值。您的示例缺少所有这些,因此可能严重受损

选项2需要一些额外的include,因此当这些头中的任何一个发生更改时,使用QAudioRx的所有内容都需要重新编译。将QAudioRx与其他类型紧密结合。在一个大项目中,这可能是重要的,但在一个小项目中,这可能并不重要——如果构建整个项目的时间以秒为单位,那么它肯定不值得

然而,我想说,你的选择1几乎从来都不是一个好主意。如果您关心减少依赖项和构建时间,请使用“请参阅”以了解相关问题:

class QAudioRx
{
public:
    QAudioRx();

private:  
    class QAudioRxImpl;
    std::unique_ptr<QAudioRxImpl> m_impl;
};
注意:我使用std::unique\u ptr时假设impl对象将被动态分配,因为这是最常见的方法,解决方案可以调整 如果对象的管理方式不同,则会被忽略

现在,所有成员变量都是impl对象的一部分,而impl对象没有在头中定义。这意味着从impl类内部访问成员是直接的,而不是通过指针,但是从QAudioRx访问成员必须执行一个间接操作来调用impl类上的函数


这仍然减少了依赖性,但使管理额外复杂性变得更简单,因为没有原始指针,因此特殊成员函数将自动执行一些合理的操作。默认情况下,它是可移动的,但不可复制,并将在析构函数中清除。

编译时依赖项和编译时依赖项之间存在权衡,这通常与所需包含文件的数量以及简单性和效率相关

选项1的编译速度更快,但几乎可以肯定运行速度较慢。每次访问成员变量时,都有一个通过指针的间接寻址,指针引用的对象必须单独分配和管理。如果分配是动态的,那么会有额外的成本,管理单独对象的额外逻辑有引入bug的风险。首先,您有原始指针,所以您必须定义或删除复制构造函数、复制赋值,可能还有析构函数,可能还有移动构造函数和移动赋值。您的示例缺少所有这些,因此可能严重受损

选项2需要一些额外的include,因此当这些头中的任何一个发生更改时,使用QAudioRx的所有内容都需要重新编译。将QAudioRx与其他类型紧密结合。在一个大项目中,这可能是重要的,但在一个小项目中,这可能并不重要——如果构建整个项目的时间以秒为单位,那么它肯定不值得

然而,我想说,你的选择1几乎从来都不是一个好主意。如果您关心减少依赖项和构建时间,请使用“请参阅”以了解相关问题:

class QAudioRx
{
public:
    QAudioRx();

private:  
    class QAudioRxImpl;
    std::unique_ptr<QAudioRxImpl> m_impl;
};
注意:我使用std::unique_ptr时假设impl对象将被动态分配,因为这是最常见的方法,如果对象的管理方式不同,则可以调整解决方案

现在,所有成员变量都是impl对象的一部分,而impl对象没有在头中定义。这意味着从impl类内部访问成员是直接的,而不是通过指针,但是从QAudioRx访问成员必须执行一个间接操作来调用impl类上的函数


这仍然减少了依赖性,但使管理额外复杂性变得更简单,因为没有原始指针,因此特殊成员函数将自动执行一些合理的操作。默认情况下,它是可移动的,但不可复制,并将在析构函数中清除。

但是,它可以这样重新写入,不能重写,因为选项2与选项1不同。这些是不同的结构,可能有不同的用途。没有什么可选择的,这取决于你现在需要什么。而且你绝对不应该根据页眉包含是否干净来设计结构。@freakish ok fair point,但是,如果要实例化成员一次且只实例化一次,则可以采用任何一种方法实现。实例的布局受外部因素(如标题的可维护性)的严重影响,这让我有点紧张。@code\u fodder是的,那么您必须问自己:哪种结构更适合我的目的?哪个更容易控制?我需要哪一个?再次强调:标题包含应该与类设计无关。@perencia-为什么会这样?我的意思是你能再解释一下吗?谢谢,即使可以这样重写,也不能重写,因为选项2与选项1不同。这些是不同的结构,可能有不同的用途。没有什么可选择的,这取决于你现在需要什么。而且你绝对不应该根据页眉包含是否干净来设计结构。@freakish ok fair point,但是,如果要实例化成员一次且只实例化一次,则可以采用任何一种方法实现。实例的布局受外部因素(如标题的可维护性)的严重影响,这让我有点紧张。@code\u fodder是的,那么您必须问自己:哪种结构更适合我的目的?哪个更容易控制?我需要哪一个?再次强调:标题包含应该与类设计无关。@perencia-为什么会这样?我的意思是你能再解释一下吗?谢谢+1,是的,这是真的,这就是为什么我开始问关于我如何处理这件事的问题。让某人推动你回到正轨是件好事——谢谢:使用指针并不意味着你必须在堆上分配对象。这是一个奇怪的想法,我经常在这里看到重复。@juanchopanza-True。但是如何在堆栈中根据作用域分配它?\@code\u fodder您可以在堆栈上分配它,或者静态分配,或者间接分配
通过在容器中创建和存储对象的其他东西在免费存储上。有一个不限成员名额的选项。你必须考虑的是对象所有权。谁拥有指针指向的对象指针?存储值时,所有权是明确的。对于指针,你必须做出决定,然后确保它是清晰的。+1,是的,这是真的,这就是为什么我开始问我如何处理这个问题的原因。让某人推动你回到正轨是件好事——谢谢:使用指针并不意味着你必须在堆上分配对象。这是一个奇怪的想法,我经常在这里看到重复。@juanchopanza-True。但它如何在堆栈中相对于作用域分配?\@code\u fodder您可以在堆栈上分配它,或者静态地分配,或者通过在容器中创建和存储对象的其他东西间接地分配到空闲存储区。有一个不限成员名额的选项。你必须考虑的是对象所有权。谁拥有指针指向的对象指针?存储值时,所有权是明确的。对于指针,你必须做出决定,然后确保它是清晰的。