Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.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++_Function_Header_Member_Inlining - Fatal编程技术网

C++ 内联还是不内联

C++ 内联还是不内联,c++,function,header,member,inlining,C++,Function,Header,Member,Inlining,我最近写了几节课;我想知道这是否是一种不好的做法,不利于性能,破坏了封装,或者在头中定义一些较小的成员函数(我确实尝试过谷歌!)是否还有其他本质上的不好之处。下面是一个例子,我写了很多这样的标题: class Scheduler { public: typedef std::list<BSubsystem*> SubsystemList; // Make sure the pointer to entityManager is zero on init //

我最近写了几节课;我想知道这是否是一种不好的做法,不利于性能,破坏了封装,或者在头中定义一些较小的成员函数(我确实尝试过谷歌!)是否还有其他本质上的不好之处。下面是一个例子,我写了很多这样的标题:

class Scheduler {
public:
    typedef std::list<BSubsystem*> SubsystemList;

    // Make sure the pointer to entityManager is zero on init
    // so that we can check if one has been attached in Tick()
    Scheduler() : entityManager(0) { }

    // Attaches a manager to the scheduler - used by Tick()
    void AttachEntityManager( EntityManager &em )
        { entityManager = &em; }

    // Detaches the entityManager from a scheduler.
    void DetachEntityManager()
        { entityManager = 0; }

    // Adds a subsystem to the scheduler; executed on Tick()
    void AddSubsystem( BSubsystem* s )
        { subsystemList.push_back(s); }

    // Removes the subsystem of a type given
    void RemoveSubsystem( const SubsystemTypeID& );

    // Executes all subsystems
    void Tick();

    // Destroys subsystems that are in subsystemList
    virtual ~Scheduler();
private:
    // Holds a list of all subsystems
    SubsystemList subsystemList;

    // Holds the entity manager (if attached)
    EntityManager *entityManager;
};
类调度程序{
公众:
typedef std::list子系统列表;
//确保init上指向entityManager的指针为零
//这样我们就可以检查勾号()中是否附加了一个
调度程序():entityManager(0){}
//将管理器附加到计划程序-由Tick()使用
无效附件所有权管理人(实体管理人和em)
{entityManager=&em;}
//从计划程序中分离entityManager。
void DetachEntityManager()
{entityManager=0;}
//将子系统添加到计划程序;在Tick()上执行
无效添加子系统(B子系统*s)
{子系统列表。向后推_;}
//删除给定类型的子系统
void RemoveSubsystem(const SubsystemTypeID&);
//执行所有子系统
无效勾号();
//销毁子系统列表中的子系统
虚拟调度程序();
私人:
//保存所有子系统的列表
子系统列表子系统列表;
//保存实体管理器(如果已附加)
EntityManager*EntityManager;
};
那么,像这样的内联函数是否有什么真正的错误,或者可以接受


(另外,我不确定这是否更适合“代码审查”网站)

它会增加可执行文件的大小,在某些情况下会导致性能下降

请记住,内联方法要求其源代码对任何使用它的人都可见(即标头中的代码)。这意味着内联方法实现中的一个小更改将导致对所有使用定义了内联方法的标头的内容进行重新编译

另一方面,这是一个小的性能提升,它对频繁调用的短方法很好,因为它可以节省调用方法的典型开销

如果您知道在哪里使用内联方法,并且不发送垃圾邮件,那么内联方法就可以了

编辑: 关于样式和封装,使用内联方法可以防止使用指向实现的指针、转发声明等。。因为代码在标题中。

内联至少有三个“缺点”:

  • 内联函数与virtual关键字不一致(我的意思是,在概念上,IMO,要么您希望用一段代码来代替函数调用,要么您希望函数调用是虚拟的,即多态的;无论如何,请参阅以了解有关何时实际可行的更多详细信息)

  • 你的二进制代码会更大

  • 如果在类定义中包含内联方法,则会显示实现细节


  • 除此之外,内联方法显然是可以的,尽管现代编译器已经足够聪明,可以在性能上有意义的情况下自行内联方法。因此,从某种意义上说,我认为最好把它完全交给编译器……类体中的方法通常是自动内联的。另外,
    inline
    是一个建议,而不是命令。编译器通常足够聪明,可以判断是否内联函数


    您可以参考这一点。

    您的所有成员函数都是一行程序,因此我认为这是可以接受的。请注意,内联函数实际上可能会减小代码大小(!!),因为优化编译器会增加(非内联)函数的大小,以使它们适合于块

    为了使代码更具可读性,我建议使用以下内联定义:

    class Scheduler
    {
        ...
    
        void Scheduler::DetachEntityManager();
    
        ...
    };
    
    
    inline void Scheduler::DetachEntityManager()
    {
        entityManager = 0;
    }
    
    在我看来,这更具可读性。

    我认为内联(如果我理解正确的话,你指的是将琐碎代码直接写入头文件的习惯,而不是编译器行为)通过两个因素帮助可读性:

  • 它将平凡方法与非平凡方法区分开来
  • 它使简单方法的效果一目了然,成为自文档化代码
  • 从设计角度来看,这并不重要。在不更改子系统列表成员的情况下,您不会更改内联方法,在这两种情况下都需要重新编译。内联不影响封装,因为该方法仍然是具有公共接口的方法


    因此,如果这个方法是一个愚蠢的单行程序,不需要冗长的文档,也不需要包含接口更改的更改,我建议使用内联。内联会增加耦合,并增加类中的“噪音” 定义,使课堂更难阅读和理解。作为一个 一般来说,内联应被视为一种优化措施, 而且只在探查器说有必要时使用

    有几个例外:我将始终内联 如果所有其他函数都是纯虚函数,则为抽象基类; 为一个空文件单独设置一个源文件似乎很愚蠢 析构函数,如果所有其他函数都是纯虚函数 没有数据成员,如果没有 还有别的变化。我偶尔会提供内联的 “结构”的构造函数—所有数据成员都在其中的类 是公共的,没有其他功能。我也不那么严格 关于避免在源文件中定义的类中内联, 耦合问题显然不适用于标题
    这种情况。

    事实上,您可以在头文件中写入所有函数,如果函数太大,编译器将自动不内联函数。把函数体写在你认为合适的地方