两个单独的“如果”,相同的条件 - 可以吗?

时间:2011-07-11 12:42:53

标签: c++ syntax

你认为哪两个更好?

if (the_condition)
{
    variable = sth;
}
else
{
    variable = sth_else;
}

if (the_condition)
{
    variable_2.doSth();
}
else
{
    variable_2.doSthElse();
}

if (the_condition)
{
    variable = sth;
    variable_2.doSth();
}
else
{
    variable = sth_else;
    variable_2.doSthElse();
}

我问这个问题,因为第二个例子显然更短。另一方面,在第一个示例中,对不同变量的操作是分开的,因此可能更容易阅读。

你认为他们中的任何一个更好吗?或者问这样一个问题是没有意义的,因为它没关系?

11 个答案:

答案 0 :(得分:45)

#2

如果情况发生变化怎么办?然后你必须在 n 的地方更新它! (并且很容易错过一个,引入微妙的,难以发现的错误。)

我个人认为#1更难阅读,因为我必须阅读每个作业的条件,因为可能不同。对于#2,我知道if主体中的所有内容都处于单一条件的上下文中 - 您可能会说条件封装了一个单一的,有凝聚力的多语句行为块。

当然,如果if正文中的语句不相关(即不是同一行为的一部分),那么它们应该是分开的{{1} }秒。但这可能并非如此:您根据初始条件(可能是一个逻辑操作)设置变量。

答案 1 :(得分:15)

无理由重复条件不好,既不是表现(可能无关紧要),也不是维护(重要)。

大多数程序员不同意你对变量操作应该分开的看法。常见的观点是控制流程应尽可能简单,第二种选择就是这种情况。

答案 2 :(得分:10)

已经给出了许多选择第二种选择的好理由,但还有另外一种:第一种选择的结构与大多数人的想法不一致。你自己的大脑是这样的吗?

If I go to the store I'll buy milk.
If I go to the store I'll buy eggs.
If I go to the store I'll get cash from the ATM.

或者喜欢这个?

If I go to the store I'll buy milk, buy eggs, and get cash from the ATM.

答案 3 :(得分:9)

答案 4 :(得分:3)

我会说取决于您的商业模式

如果保证两个变量始终将其值设置为“一个”,那么应该使用第二种方法来反映(并且可能添加注释以强化这一点)。

否则,如果两个条件发生相同(但没有要求说它们将来不会分歧),应该使用第一种方法。

无论上述哪一种,在方便的情况下用三元运算符替换条件赋值也会产生更短的代码。

答案 5 :(得分:3)

我个人的偏好:

T const variable = foo(v1, v2);
T2 const variable2 = bar(v1, v2);

声明const的变量无法更改(啊!),因此调试变得更加容易,因为您可以假设它不会更改(否则编译器会抱怨)。

一般来说,我建议编写简短的方法,但简短并不意味着“紧凑”,这意味着执行的任务很少。

答案 6 :(得分:2)

#2更干净,但如果代码中有明确的主路径,并且额外的变量分配不对,我常常会执行以下操作生成更多的工作。

variable = sth_else;
variable_2 = sth_even_more_different;

if (the_condition)
{
    variable = sth;
    variable_2 = sth_different;
}

其他简写,有人认为这是一种不好的做法。不要使用太多:

variable = the_condition ? sth : sth_else;
variable_2 = the_condition ? sth_different : sth_event_more_different;

答案 7 :(得分:1)

我会更好地考虑第二。在一个块中将特定条件的逻辑分组可以在将来更容易维护。一目了然,读者可以将给定的条件控制流与其对应的程序逻辑相关联,而不必继续向下读取页面。分组还允许更改单独发生,而不必担心更新其他块。

答案 8 :(得分:1)

我可以提倡另一种方法吗?

您似乎在每个if-body中分配相同的变量集。一组变量听起来对我来说至少是POD aggregate

struct Foo {
    int variable;
    int variable_2;
};

变体I

然后

const Foo alpha = {sth, sth_different},
          bravo = {sth_else, sth_even_more_different};
...
Foo foo;
if (the_condition)
    foo = alpha;
else
    foo = bravo;

// or something like  const Foo foo=get(the_condition);

变式II

或者更具有const变量的版本,具有较少的可变状态和实际初始化:

const Foo alpha = {sth, sth_different},
          bravo = {sth_else, sth_even_more_different};
...
const Foo foo = the_condition ? alpha
                              : bravo;

变体III

或者在基准测试,时间关键,瓶颈代码中(但完全取决于,基准测试),这是一个很好的旧查找表:

const Foo foos[] = {{sth, sth_different},
                    {sth_else, sth_even_more_different}};
...
const Foo foo = foos[the_condition?0:1];

变式IV

根据您的实际使用情况,反转事物可能更自然:

class Foo {
public:
    Foo (bool condition) : [...] {...}
};

附录

执行初始化

引入类/结构的好处是它还可以强制执行不忘记初始化:

class Foo {
    Foo (int var_a, int var_b) : var_a(var_a), var_b(var_b) {}

    const int var_a;
    const int var_b;

private:
    Foo(); // or "= delete" in upcoming standard
};

效果

有趣的是,即使是3.x行的旧gcc也会编译两个变体......

#include <iostream>
int pure() {                  
    bool cond;
    std::cin >> cond;        
    int a, b;    
    a = cond ? 0 : 2;
    b = cond ? 1 : 3;        
    std::cout << a << "," << b << std::endl;
}

struct Foo {
    int a, b;
};
int agg() {
    const Foo alpha = { 0, 1 },
              bravo = { 2, 3 };                  
    bool cond;
    std::cin >> cond;        
    const Foo result = cond ? alpha : bravo;        
    std::cout << result.a << "," << result.b << std::endl;
}

...只有2-6个装配说明,相比总共80-120个指令。不幸的是,我现在缺乏现代的g ++。但是已经使用这个真正过时的编译器,使用聚合对我来说没有味道(如果我找到时间,我会在稍后提供结果)。

答案 9 :(得分:1)

第二种选择通常更好。整个功能的控制流程通常具有更重要的意义。许多项目都有规则将决策逻辑降至最低。该决策逻辑是一个可测量的数量,McCabe的圈复杂度或其一些变体,如扩展的圈复杂度。

评论风格
摆脱写作的习惯是个好主意

if (the_condition)
  variable = sth;
else
  variable = sth_else;

始终使用牙箍。添加大括号不会改变已编译的代码。作者添加这些括号的成本很低;使用智能编辑器,成本可能不存在。减少愚蠢,难以追查错误的潜在节省是巨大的。由于这个原因,有许多项目使上述形式的代码非法。总是使用牙箍。

答案 10 :(得分:0)

我会添加一个我认为最不值得考虑的变体。如果你只在一个地方使用它来获得单一的二元条件,它可能有点过分。如果你可能遇到更大的复杂性或者经常使用它,它可能会更有用。

// type for pointer to member function
typedef void (*variable_2_type::pmf)();

// type holding value and action to execute:
struct result { 
    T value;
    pmf action;
};

// table of values/actions:
result results[] = { 
    {sth_else, &variable_2_type::doSthElse },
    {sth,      &variable_2_type::doSth }
};

// use the table:
variable = results[condition]. value;
variable_2.*(results[condition].action)();