根据条件声明大变量的方法

时间:2019-11-04 11:58:38

标签: c++

我仔细阅读了C ++核心准则,并遇到了以下规则:“在声明具有变量值的变量之前,不要声明变量” https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#es22-dont-declare-a-variable-until-you-have-a-value-to-initialize-it-with

它将以下代码描述为错误的代码:

SomeLargeType var;

if (cond)   // some non-trivial condition
    Set(&var);
else if (cond2 || !cond3) {
    var = Set2(3.14);
}
else {
    var = 0;
    for (auto& e : something)
        var += e;
}

不幸的是,这一点未能描述解决此确切问题的方法。有时,您只需要根据条件不同地初始化大对象。 我想到的唯一绕过的事情是:

SomeLargeType * var;

if (cond)   // some non-trivial condition
    var = new SomeLargeType(123);
else if (cond2 || !cond3) {
    var = new SomeLargeType(3.14);
}

但是,即使我使用了智能指针,这仍然感觉到不必要/不安全,最重要的是,比起最初的方法更糟糕。

什么是最佳解决方案?

3 个答案:

答案 0 :(得分:5)

您可以使用一个功能。另外,不要使用具有所有权的裸露的指针(我也假设对此有一个指导原则)。示例:

SELECT Ward, LocalAuthority, Fiscal, DR,
CASE WHEN SUM(DR) OVER(PARTITION BY localauthority, fiscal ORDER BY fiscal asc) = 0 THEN 0 ELSE CAST(DR*100.0 / SUM(DR) OVER(PARTITION BY  localauthority,fiscal ORDER BY fiscal) AS Decimal (10,2)) END AS [DR%]
FROM (
      SELECT Fiscal, LocalAuthority, Ward, SUM(CASE WHEN code = 'DR' THEN 1 ELSE 0 END) AS DR
      FROM [dbo].[Table]
      WHERE datetimeofcall >='2014-04-01' 
      GROUP BY ward, localauthority, fiscal
     ) AS A

如果无法重用此功能,则可能适合使用lambda,如Sopel

所示

答案 1 :(得分:3)

首先,原始示例代码中没有未定义的行为 :(在最后的else块中)将处理所有可能的条件。但是,到目前为止,答案中存在潜在不确定的行为,因为它们实际上没有初始化和返回{的情况下,替换了上述else块中的“ good”代码{1}},以后可能会尝试取消引用。

此外,这里实际上没有必要通过用指针替换 instance 变量来使问题复杂化(这也会改变代码的性质/逻辑)。

使用lambda(如link provided by StaceyGirl中的建议)无疑是一个好方法(可能是最好的方法,但这可能是主观的)。但是,为了使逻辑与原始代码相同,可以将lambda应用于对象,而不是指针,如下所示:

nullptr

在这里,与原始代码(首先调用默认构造函数,然后调用其他三个构造函数)不同,SomeLargeType var = [&]() { if (cond) { // some non-trivial condition SomeLargeType v1; Set(&v1); return v1; } else if (cond2 || !cond3) { SomeLargeType v2 = Set2(3.14); return v2; } else { SomeLargeType v3 = 0; for (auto& e : something) var += e; return v3; } }(); 的构造函数只会被称为一次¹,没有不确定的行为。 我认为,这是对(可能非常昂贵的)默认构造函数的首次调用,这就是被称为“错误代码”示例的原因。

¹如果对构造函数的调用频率有任何疑问,我可以提供完整的MCVE(进行一些小的修改,以避免未定义的SomeLargeObject行)。

答案 2 :(得分:2)

立即调用的lambda可以替代命名函数。

If down = true Then
      Me.location = cursor.position
 End if

请注意,某些类型可能不提供默认的构造函数,在这种情况下,不使用装箱类型就不可能进行延迟初始化。

当类型不可构造时,这也可以提高性能。 the documentation of TimeSpan.ToString