我仔细阅读了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);
}
但是,即使我使用了智能指针,这仍然感觉到不必要/不安全,最重要的是,比起最初的方法更糟糕。
什么是最佳解决方案?
答案 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