缩进级别

时间:2009-01-29 13:56:44

标签: c++

您认为多少级别的缩进合理?

我觉得拥有带有4/5 +级别缩进的C ++函数通常是件坏事。这意味着你必须在心理上始终跟踪4/5 +事物。

我的意见是否合理?

(是的,我可以通过不缩进来避免多级缩进:)

12 个答案:

答案 0 :(得分:8)

我同意你的看法。如果一个函数有超过4或5个嵌套的if / switch / loop / try语句,那么它的一部分应该被提取到它们自己的函数中。

这将使代码更具可读性,因为提取的函数名称通常比代码本身更具描述性。

答案 1 :(得分:5)

这完全取决于您的代码试图解决的问题。有时你别无选择,只能有很深的缩进程度,尽管肯定是code smell

我认为你是正确的4或5级左右是合理的,更多,你可能应该寻求重构该方法。

值得注意的是,人们多年来一直在努力量化代码质量和设计指标。其中一个更常见的指标是cyclomatic complexity

答案 2 :(得分:2)

实际上,不是那些对不可读代码贡献最多的缩进级别数,而是你正在查看的模块/函数/方法的长度。

当然,长节通常具有更多级别的缩进,因为代码块是内联使用而不是分解,所以它们之间存在关系。就个人而言,我认为如果一个方法有超过几个屏幕代码和超过6个级别的缩进,那就有气味。

答案 3 :(得分:0)

我认为这取决于具体情况,但通常你会想要更少的嵌套。

嵌套循环可以扼杀性能,嵌套if语句可以减少到更低的级别。

问题是,您经常遇到试图在开发过程中过早优化的问题。我认为在进行3级以上的嵌套之前,你应该花点时间考虑一下这些可能性。

答案 4 :(得分:0)

关于缩进,我唯一的烦恼是使用两个关键字,一个取决于另一个。例如:

switch (c) {
    case 'x':
       foo = bar;

这很糟糕,你不能在开关外面有一个案例,所以:

switch (c) {
case 'x':
    foo = bar;

..会好得多。在使用if / else if / else的开关中,缩进往往会变得疯狂。我还强烈建议在缩进时保持80(最多110列限制)。没有人喜欢向右滚动30列以查看您正在做什么,并且返回30列以查看您如何处理结果:)不要介意那些在服务器上以哑80x25控制台模式编辑代码的可怜的灵魂。

答案 5 :(得分:0)

虽然我要说的是纯粹的C观点,但它也可能适用于C ++。我喜欢Linux内核编码风格,即:8个字符宽的标签缩进(自然标签)以及80x25终端上的多个缩进级别(不超过80个字符宽度,即)。

答案 6 :(得分:0)

过多的缩进可能是您应该重构的一个标志:创建一些具有良好名称的小方法。这样你就可以将逻辑分解成更容易被吞噬的小块。

答案 7 :(得分:0)

这涉及功能应该有多长的问题。如果你将函数体保持在10行或更少,那么很难获得太多的缩进级别。

我认为4或5级太多了。你几乎可以肯定地将一些内部循环或条件分解成它们自己的函数。

我觉得自己有三个级别的缩进感到不安。即使是两个级别也会让我重新考虑我正在做的事情。

答案 8 :(得分:0)

只要您可以在编辑器中同时看到所有打开和关闭括号,就可以进行多级缩进。

在实践中,这往往会限制你最多4级。

答案 9 :(得分:0)

但需要注意的是,有些嵌套级别是必要的,不应该被抽象出来。

如果你对4D阵列进行某种强力迭代,那么你自动有四级嵌套,如果有一个IF语句,那么你就有五个级别而没有特别复杂的代码段。

因此,嵌套的级别不一定是问题,它是每个嵌套级别的复杂性。如果你正在混合WHILE,FOREACH,IF和SWITCH,那么也许你应该把它们煮沸。

基本点是嵌套水平并不总是复杂性的指标。

答案 10 :(得分:0)

IIRC,Linus Torvalds会同意你的看法。我相信他坚持使用8个空格的缩进和一个80个字符的行长度来代替linux内核代码。当您在该方案下达到4或5级缩进时,您的代码看起来会非常糟糕。为了保持可读性,您不得不尝试重构代码。

答案 11 :(得分:0)

我以前认为Linus在这方面有点难过,因为他说不超过3级或者你的代码被破坏了,但是,遵循这个原则帮助了我很多关于我的控制流程的推理。也就是说,我必须以不同的方式解释它。直观的解释是你应该创建越来越多的小功能。我不建议将这个想法发挥到极致,因为这会使你的控制流和副作用同样难以推理,当所有副作用被函数调用遮住时会引导你到处都是。

极大地帮助了我的是支持延迟处理和更简单的循环。以此为例:

// Remove vertices from mesh.
for each vertex in vertices.to_remove:
{
    for each edge in vertex.edges:
    {
        for each face in edge.faces:
        {
             face.remove_edge(edge);
             if (face.size() < 3)
                   face.remove();
        }
        edge.remove();
    }
    vertex.remove();
}

上面有4级缩进的那个怪异的东西很笨拙(当它不是伪编码形式时可能需要更新纹理贴图等等,更需要甚至更多级别的缩进)。我们可以这样做:

for each vertex in vertices.to_remove:
{
    for each edge in vertex.edges:
        edges_to_remove.insert(edge);
}

for each edge in edges_to_remove:
{
    for each face in edge.faces:
        faces_to_rebuild.insert(face, edge);
}

for each face,edge in faces_to_rebuild:
{
    face.remove_edge(edge);
    if (face.size() < 3)
         face.remove();
}

for each edge in edges_to_remove:
    edge.remove();

for each vertex in vertices_to_remove:
    vertex.remove();

虽然这涉及更多的数据传递和一些额外的状态,但它使每个循环更简单。当我们拥有这些更简单的循环时,它们变得更容易并行化,并且内存访问模式可以开始采用具有良好数据结构的缓存友好性质。

我发现支持这种类型的延迟处理不仅减少了这些缩进,而且还简化了我理解代码正在做什么的能力,因为控制流很简单并且它们都只引起一种类型的统一边影响。它使得更容易看到每个循环正在做什么并且理解它是否正确地做出正确的事情,因为每个循环都致力于引起一种类型的副作用,而不是许多不同类型的副作用。令人惊讶的是,尽管有额外的工作,但它通常可以提高缓存一致性,并为多线程和SIMD开辟了新的大门,最终我获得了比我开始时更有效的结果。