你认为哪两个更好?
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();
}
我问这个问题,因为第二个例子显然更短。另一方面,在第一个示例中,对不同变量的操作是分开的,因此可能更容易阅读。
你认为他们中的任何一个更好吗?或者问这样一个问题是没有意义的,因为它没关系?
答案 0 :(得分:45)
如果情况发生变化怎么办?然后你必须在 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;
};
然后
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);
或者更具有const变量的版本,具有较少的可变状态和实际初始化:
const Foo alpha = {sth, sth_different},
bravo = {sth_else, sth_even_more_different};
...
const Foo foo = the_condition ? alpha
: bravo;
或者在基准测试,时间关键,瓶颈代码中(但完全取决于,基准测试),这是一个很好的旧查找表:
const Foo foos[] = {{sth, sth_different},
{sth_else, sth_even_more_different}};
...
const Foo foo = foos[the_condition?0:1];
根据您的实际使用情况,反转事物可能更自然:
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)();