内联或不内联

发布于 2024-11-27 04:13:18 字数 1289 浏览 1 评论 0原文

我最近一直在写一些课程;我想知道这是否是不好的做法,对性能不利,破坏封装,或者在标头中实际定义一些较小的成员函数是否有其他本质上的坏处(我确实尝试过Google!)。这是我用很多这样的内容编写的标头的示例:

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;
};

那么,像这样的内联函数是否真的有错误,或者可以接受吗?

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

I've been writing a few classes lately; and I was wondering whether it's bad practice, bad for performance, breaks encapsulation or whether there's anything else inherently bad with actually defining some of the smaller member functions inside a header (I did try Google!). Here's an example I have of a header I've written with a lot of this:

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;
};

So, is there anything that's really wrong with inlining functions like this, or is it acceptable?

(Also, I'm not sure if this'd be more suited towards the 'code review' site)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

揪着可爱 2024-12-04 04:13:18

内联增加了耦合,并增加了类中的“噪音”
定义,使课程更难阅读和理解。作为一个
一般规则,内联应被视为一种优化措施,
并且仅在探查器认为有必要时才使用。

有一些例外:我总是内联虚拟析构函数
如果所有其他函数都是纯虚函数,则为抽象基类;
仅仅为一个空的文件创建一个单独的源文件似乎很愚蠢
析构函数,并且如果所有其他函数都是纯虚函数,并且
没有数据成员,析构函数不会在没有数据成员的情况下改变
其他事情正在改变。我偶尔会提供内联
“结构”的构造函数——其中所有数据成员的类
是公共的,没有其他功能。我也比较不严谨
关于避免在源文件中定义的类中内联,
而不是标题——耦合问题显然不适用于
那种情况。

Inlining increases coupling, and increases "noise" in the class
definition, making the class harder to read and understand. As a
general rule, inlining should be considered as an optimization measure,
and only used when the profiler says it's necessary.

There are a few exceptions: I'll always inline the virtual destructor of
an abstract base class if all of the other functions are pure virtual;
it seems silly to have a separate source file just for an empty
destructor, and if all of the other functions are pure virtual, and
there are no data members, the destructor isn't going to change without
something else changing. And I'll occasionally provide inlined
constructors for "structures"—classes in which all data members
are public, and there are no other functions. I'm also less rigorous
about avoiding inline in classes which are defined in a source file,
rather than a header—the coupling issues obviously don't apply in
that case.

萤火眠眠 2024-12-04 04:13:18

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

为了使您的代码更具可读性,我建议使用内联定义,如下所示:

class Scheduler
{
    ...

    void Scheduler::DetachEntityManager();

    ...
};


inline void Scheduler::DetachEntityManager()
{
    entityManager = 0;
}

在我看来,这更具可读性。

All of your member functions are one-liners, so in my opinion thats acceptable. Note that inline functions may actually decrease code size (!!) because optimizing compilers increase the size of (non-inline) functions in order to make them fit into blocks.

In order to make your code more readable I would suggest to use inline definitions as follows:

class Scheduler
{
    ...

    void Scheduler::DetachEntityManager();

    ...
};


inline void Scheduler::DetachEntityManager()
{
    entityManager = 0;
}

In my opinion thats more readable.

风流物 2024-12-04 04:13:18

我认为内联(如果我理解正确的话,你的意思是把简单的代码直接写入头文件的习惯,而不是编译器的行为)通过两个因素来提高可读性:

  1. 它区分了简单的方法和非简单的方法。
  2. 它使琐碎方法的效果一目了然,成为自记录代码。

从设计角度来看,这并不重要。您不会在不更改subsystemList 成员的情况下更改内联方法,并且在这两种情况下都需要重新编译。内联不会影响封装,因为该方法仍然是具有公共接口的方法。

因此,如果该方法是一种愚蠢的单行方法,不需要冗长的文档或可以想象的不包含接口更改的更改需求,我建议采用内联。

I think inlining (if I understood you right, you mean the habit of writing trivial code right into the header file, and not the compiler behaviour) aids readability by two factors:

  1. It distinguishes trivial methods from non-trivial ones.
  2. It makes the effect of trivial methods available at a glance, being self-documenting code.

From a design POV, it doesn't really matter. You are not going to change your inlined method without changing the subsystemList member, and a recompile is necessary in both cases. Inlining does not affect encapsulation, since the method is still a method with a public interface.

So, if the method is a dumb one-liner without a need for lengthy documentation or a conceivable need of change that does not encompass an interface change, I'd advise to go for inlining.

世态炎凉 2024-12-04 04:13:18

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

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

另一方面,它的性能提升很小,对于经常调用的短方法很有好处,因为它会节省调用方法的典型开销。

如果您知道在哪里使用内联方法并且不向它们发送垃圾邮件,那么内联方法就很好。

编辑:
关于样式和封装,使用内联方法可以防止您使用诸如实现指针、前向声明等之类的东西,因为您的代码位于标头中。

It will increase executable size and in some occasions this will lead to worse performance.

Keep in mind that an inline method requires it's source code to be visible to whoever uses it (ie. code in the header) this means that a small change in the implementation of your inlined methods will cause a recompilation on everything that uses the header where the inline method was defined.

On the other hand, it is a small performance increase, it's good for short methods that are called really frequently, since it will save you the typical overhead of calling to methods.

Inline methods are fine if you know where to use them and don't spam them.

Edit:
Regarding style and encapsulation, using inline methods prevents you from using things like Pointer to implementation, forward declarations, etc.. since your code is in the header.

星軌x 2024-12-04 04:13:18

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

  1. 内联函数与 virtual 关键字不一致(我的意思是从概念上讲,IMO,要么你想要一段代码来代替函数调用,要么你想要函数调用是虚拟的,即多态的;另请参阅 了解有关何时有意义的更多详细信息);

  2. 你的二进制代码将会更大;

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

除此之外,内联方法显然是可以的,尽管现代编译器确实已经足够聪明,可以在对性能有意义时自行内联方法。所以,从某种意义上说,我认为最好将其完全留给编译器......

Inlining has three "drawbacks" at least:

  1. inline functions are at odds with the virtual keyword (I mean conceptually, IMO, either you want a piece of code to be substituted for the function call, or you want the function call to be virtual, i.e. polymorphic; anyway, see also this for more details as to when it could make sense practically);

  2. your binary code will be larger;

  3. if you include the inline method in the class definition, you reveal implementation detail.

Apart from that it is plainly ok to inline methods, although it is also true that modern compilers are already sufficiently smart to inline methods on their own when it makes sense for performance. So, in a sense I think it is better to leave it to the compiler altogether...

小红帽 2024-12-04 04:13:18

class 体内的方法通常会自动内联。另外,inline 是一个建议,而不是一个命令。编译器通常足够聪明,可以判断是否内联函数。

您可以参考这个类似问题

Methods inside class body are usually inline automatically. Also, inline is a suggestion and not a command. Compilers are generally smart enough to judge whether to inline a function or not.

You can refer to this similar question.

梦屿孤独相伴 2024-12-04 04:13:18

事实上你可以把所有的函数都写在头文件中,如果函数太大编译器会自动不内联函数。只需将函数体写在您认为最合适的地方,让编译器决定。如果你真的坚持使用 __forceinline 或类似的东西(我认为这是 MS 特有的)来内联函数,那么 inline 关键字也经常被忽略。

In fact you can write all your functions in the header file, if the function is too large the compiler will automatically not inline the function. Just write the function body where you think it fits best, let the compiler decide. The inline keyword is ignored often as well, if you really insist on inlining the function use __forceinline or something similar (I think that is MS specific).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文