C++ “两个独立的”;如果';s、 同样的条件——可以吗?

C++ “两个独立的”;如果';s、 同样的条件——可以吗?,c++,syntax,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;
}
else
{
    variable = sth_else;
}

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

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


你认为他们中的任何一个更好吗?或者问这样一个无关紧要的问题是没有意义的?

毫无理由地重复条件是不好的,无论是性能(可能不重要)还是维护(确实重要)

大多数程序员不同意您关于变量操作应该分开的观点。通常的观点是,控制流应该尽可能简单,第二个选项就是这样

#2 如果情况改变怎么办?然后你必须在n个地方更新它!(而且很容易漏掉一个,引入了微妙的、难以发现的bug。)

我个人觉得#1更难阅读,因为我必须阅读每个作业的条件,因为它可能不同。有了#2,我知道,
if
主体中的所有内容都在单个条件的上下文中——您可以说,该条件封装了单个、内聚的多语句行为块


当然,如果
if
的主体中的语句是不相关的(即不是同一行为块的一部分),那么它们应该位于单独的
if
s中。这可能不是这样的:但是,你要根据初始条件(这可能是一个逻辑操作)设置变量。

< P>我会考虑<强>第二个/强>更好。将特定条件的逻辑分组到一个块中,便于将来的维护。只要看一眼代码,读者就可以将给定的条件控制流与其相应的程序逻辑相关联,而不必继续往下读。分组还允许单独进行更改,而不必担心更新其他块。

我想说这取决于您的业务模式

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

否则,如果两个条件恰好相同(但没有要求它们将来不能分离),则应使用第一种方法


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

我个人的偏好:

T const variable = foo(v1, v2);
T2 const variable2 = bar(v1, v2);
声明的变量
const
无法更改(啊!),因此调试变得非常容易,因为您可以假设它不会更改(否则编译器会抱怨)


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

我可以提倡另一种方法吗

在每个if体中,您似乎分配给同一组变量。变量集在我看来至少像一个
POD聚合

struct Foo {
    int variable;
    int variable_2;
};

变体一 然后


变式二 或者是更稳定的版本,具有更少的可变状态和实际初始化:

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;
}
#包括
int pure(){
布尔康德;
标准:cin>>条件;
INTA,b;
a=秒?0:2;
b=条件1:3;

std::cout第二种选择通常更好。通常更重要的是整个功能的控制流。许多项目都有规则将决策逻辑降到最低。决策逻辑是一个可测量的量,McCabe的圈复杂度或它的一些变体,如扩展圈复杂度泰

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

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

始终使用大括号。添加大括号几乎不会改变编译后的代码。添加这些大括号对作者的成本是最低的;使用智能编辑器,成本可能是不存在的。减少愚蠢的、难以追踪的错误的潜在节约是巨大的。有很多项目使上述形式的代码非法,因为对于这一点。始终使用大括号。

紧凑型版本;我发现这是最可读的,通常是我如何处理我的代码…当然是YMMV。)

不是特定于任何特定的答案,请记住(在结果可能被多次使用的情况下),将结果分配给适当范围的变量是一种良好的做法(如果它们是暂时的,则为本地变量;如果它们是永久的,则为对象或类(静态)属性)以揭示结果概念性质的方式命名(例如,非变量1和变量2:D)

通过只根据需要频繁地求值,您将使代码在概念上更加清晰(假设您确实为分配求值的变量提供了良好的名称),并且编译后的代码通常效率更高(而且几乎永远不会降低效率)

[感谢Peter Wone在评论中建议关于多重评估的观点应该更加明确。]


也可以使用以下各项:

        switch (the_condition)
        {
            case true:
                variable1 = sth;
                variable2 = sth_else;
                break;

            case false:
                variable1 = sth_different;
                variable2 = sth_even_more_different;
                break;

        }
虽然我认为这是一个罕见的合适的解决方案,但我提到它是为了完整性,因为我没有
if (the_condition)
  variable = sth;
else
  variable = sth_else;
// the safest way; it protects you from unexpected results in cases
// where the evaluation of "the_condition" has side-effects, or where
// it may be changed in the future to have them (as can often happen, 
// for instance, when a class field is changed to a property)
var theCondition = the_condition;

variable1 = theCondition ? sth           : sth_else;
variable2 = theCondition ? sth_different : sth_even_more_different;

// if evaluating "the_condition" has no side-effects, and you can be
// fairly sure it never will, then you can do this, but be careful:
variable1 = the_condition ? sth           : sth_else;
variable2 = the_condition ? sth_different : sth_even_more_different;
        switch (the_condition)
        {
            case true:
                variable1 = sth;
                variable2 = sth_else;
                break;

            case false:
                variable1 = sth_different;
                variable2 = sth_even_more_different;
                break;

        }
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;
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.
// 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)();