Hex*_*gon 55 c++ warnings assertions
有时局部变量的唯一目的是在assert()中检查它,就像这样 -
int Result = Func();
assert( Result == 1 );
Run Code Online (Sandbox Code Playgroud)
在Release版本中编译代码时,通常会禁用assert(),因此此代码可能会生成有关Result已设置但从未读取的警告.
可能的解决方法是 -
int Result = Func();
if ( Result == 1 )
{
assert( 0 );
}
Run Code Online (Sandbox Code Playgroud)
但它需要太多的打字,在眼睛上并不容易,并且导致总是检查条件(是的,编译器可以优化检查,但仍然).
我正在寻找一种替代方法来表达这个assert()的方式不会导致警告,但仍然易于使用并避免更改assert()的语义.
(在此区域代码中使用#pragma禁用警告不是一种选择,并且降低警告级别以使其消失也不是一种选择......).
Gra*_*row 51
我们使用宏来明确指出何时未使用的东西:
#define _unused(x) ((void)(x))
Run Code Online (Sandbox Code Playgroud)
然后在你的例子中,你有:
int Result = Func();
assert( Result == 1 );
_unused( Result ); // make production build happy
Run Code Online (Sandbox Code Playgroud)
这样(a)生产构建成功,并且(b)在代码中显而易见的是变量未被设计使用,而不是仅仅被遗忘.当不使用函数的参数时,这尤其有用.
小智 27
我无法给出比这更好的答案,解决这个问题,还有更多:
#ifdef NDEBUG
#define ASSERT(x) do { (void)sizeof(x);} while (0)
#else
#include <assert.h>
#define ASSERT(x) assert(x)
#endif
Run Code Online (Sandbox Code Playgroud)
您可以创建另一个允许您避免使用临时变量的宏:
#ifndef NDEBUG
#define Verify(x) assert(x)
#else
#define Verify(x) ((void)(x))
#endif
// asserts that Func()==1 in debug mode, or calls Func() and ignores return
// value in release mode (any braindead compiler can optimize away the comparison
// whose result isn't used, and the cast to void suppresses the warning)
Verify(Func() == 1);
Run Code Online (Sandbox Code Playgroud)
int Result = Func();
assert( Result == 1 );
Run Code Online (Sandbox Code Playgroud)
这种情况意味着在发布模式下,您真的想要:
Func();
Run Code Online (Sandbox Code Playgroud)
但是Func
非void,即它返回一个结果,即它是一个查询.
据推测,除了返回一个结果,Func
修改一些东西(否则,为什么要打扰它而不使用它的结果?),即它是一个命令.
通过命令查询分离原则(1),Func
不应该同时是命令和查询.换句话说,查询不应该有副作用,命令的"结果"应该由对象状态的可用查询表示.
Cloth c;
c.Wash(); // Wash is void
assert(c.IsClean());
Run Code Online (Sandbox Code Playgroud)
比.更好
Cloth c;
bool is_clean = c.Wash(); // Wash returns a bool
assert(is_clean);
Run Code Online (Sandbox Code Playgroud)
前者没有给你任何警告,后者确实如此.
所以,简而言之,我的回答是:不要写这样的代码:)
更新(1):您询问了有关命令查询分离原则的参考.维基百科信息量很大.我在Bertrand Meyer的第二版"面向对象软件构建"中读到了这种设计技术.
更新(2): j_random_hacker注释"OTOH,每个"命令"先前返回值的函数f()现在必须设置一些变量last_call_to_f_succeeded或类似".这仅适用于在合同中不承诺任何内容的函数,即可能"成功"或未成功的函数,或类似的概念.使用契约设计,相关数量的函数将具有后置条件,因此在"Empty()"之后,对象将是"IsEmpty()",并且在"Encode()"之后,消息字符串将是"IsEncoded()",无需检查.以同样的方式,并且有些对称,在每次调用过程"X()"之前,不要调用特殊函数"IsXFeasible()"; 因为你通常会在设计中知道你在通话时已经达到了X的先决条件.
使用 C++17 我们可以做到:
[[maybe_unused]] int Result = Func();
Run Code Online (Sandbox Code Playgroud)
尽管与断言替换相比,它涉及一些额外的输入。看到这个答案。
注意:添加此内容是因为这是谷歌第一次点击“c++断言未使用的变量”。
对于最新的C ++,我只会说:
[[maybe_unused]] int Result = Func();
assert( Result == 1 );
Run Code Online (Sandbox Code Playgroud)
有关此属性的更多详细信息,请参见https://en.cppreference.com/w/cpp/language/attributes/maybe_unused。
与(void)Result
技巧相比,我更喜欢它,因为您可以直接修饰变量声明,而不是事后才添加。
归档时间: |
|
查看次数: |
16868 次 |
最近记录: |