在Visual Studio中,我经常仅将对象用于RAII目的。例如:
ScopeGuard close_guard = MakeGuard( &close_file, file );
close_guard 的目的是确保文件在函数退出时关闭,不在其他任何地方使用。但是,Visual Studio向我发出警告,“局部变量已初始化但未引用”。我想针对这个具体案例关闭此警告。
你如何处理这种情况? Visual Studio认为这个对象没用,但这是错误的,因为它有一个非平凡的析构函数。
我不想为此使用 #pragma warning 指令,因为即使出于正当理由它也会关闭此警告。
答案 0 :(得分:8)
如果您的对象有一个非平凡的析构函数,Visual Studio应该不给您那个警告。以下代码不会在VS2005中生成任何警告,警告会一直向上(/ W4):
class Test
{
public:
~Test(void) { printf("destructor\n"); }
};
Test foo(void) { return Test(); }
int main(void)
{
Test t = foo();
printf("moo\n");
return 0;
}
评论析构函数会发出警告;代码原样不是。
答案 1 :(得分:5)
方法1:使用#pragma warning
指令。
#pragma warning
允许选择性地修改编译器警告消息的行为。
#pragma warning( push )
#pragma warning( disable : 4705 ) // replace 4705 with warning number
ScopeGuard close_guard = MakeGuard( &close_file, file );
#pragma warning( pop )
此代码保存当前警告状态,然后禁用特定警告代码的警告,然后恢复上次保存的警告状态。
方法2 :使用如下的解决方法。 Visual Studio会很开心,你也会这样。此解决方法用于许多Microsoft示例以及其他项目中。
ScopeGuard close_guard = MakeGuard( &close_file, file );
close_guard;
或者您可以创建#define
来解决警告问题。
#define UNUSED_VAR(VAR) VAR
...
ScopeGuard close_guard = MakeGuard( &close_file, file );
UNUSED_VAR(close_guard);
有些用户声称所提供的代码不起作用,因为ScopeGuard是typedef。这个假设是错误的。
http://www.ddj.com/cpp/184403758
根据C ++标准,a 用临时初始化的引用 value使临时值生效 在参考的生命周期 本身。
答案 2 :(得分:3)
我们使用:
static_cast<void>(close_guard);
表示编译器抱怨的变量。
答案 3 :(得分:3)
在某些VC ++头文件中,MS定义了一个宏:
#define UNUSED(x) x
用过:
ScopeGuard close_guard = MakeGuard( &close_file, file );
UNUSED(close_guard);
这使警告沉默,并记录下来。
答案 4 :(得分:3)
在这种情况下我会一直使用宏:
#define SCOPE_GUARD(guard, fn, param) \
ScopeGuard guard = MakeGuard(fn, param); \
static_cast<void>(guard)
现在你的代码很简洁:
SCOPE_GUARD(g1, &file_close, file1);
SCOPE_GUARD(g2, &file_close, file2);
此方法的一个优点是,稍后您可以添加__LINE__
,__func__
等,以便在以后需要时记录保护操作。
答案 5 :(得分:2)
嗯,在这种情况下,ScopeGuard实际上是引用类型的typedef。不幸的是,这不会起作用。
这不意味着整个ScopeGuard不起作用,因为在这种情况下析构函数不会被调用吗???
答案 6 :(得分:1)
您只能使用
来围绕该行代码设置#pragma警告的范围#pragma warning(push)
#pragma warning(disable:XXXX)
your code here;
#pragma warning(pop)
或
#pragma warning(disable:XXXX)
your code here;
#pragma warning(default:XXXX)
您也可以在上面的代码行之后使用UNREFERENCED_PARAMETER(close_guard);
。
答案 7 :(得分:1)
我想在实践中,我会非常谨慎地使用#pragma disable ...或'UNUSED'。但是,作为一项主要规则,代码应保持清除警告,即使以一些额外的批量为代价。它应该在不同平台和操作系统上的多个不同编译器中编译而不会发出警告。如果没有,代码必须修复,以便它可以。维护在gcc -Wall级别生成警告的代码不是一个好主意。
编译器警告是您的朋友,应该注意事项或原则。即使它意味着事情必须以更笨重和更冗长的方式实施。从长远来看,为代码的移植,维护和永远存在而付出的代价......
答案 8 :(得分:0)
尝试将“volatile”添加到ScopeGuard声明中。
答案 9 :(得分:0)
我使用上面的smink帖子并且只需添加我在#define旁边贴一条评论//用于在visual studio中禁止警告[警告号码]
答案 10 :(得分:0)
您可以显式创建ScopeGuardImpl1对象,前提是在您使用的情况下没有那么多参数,结果是不可读的。这样你就可以避免VS警告显然无法理解的引用初始化 - 临时。成本是必须手写拼写,而不是让MakeGuard模板变得神奇。
答案 11 :(得分:-3)
这里的核心问题似乎确实是编译器并不完全理解你的目的...这似乎是在C ++中使用作用域语义来获取一些代码,当一个变量被释放时调用它,即使它是没被使用。对?这种机制本身让我感到边缘......编译器应该有权删除未使用的变量,但C ++构造语义真的会让这些事情变得混乱。没有其他方法可以做到不那么狡猾吗?