【问题标题】:Concerning RAII: How to prevent errors caused by accidentally creating a temporary?关于 RAII:如何防止意外创建临时文件导致的错误?
【发布时间】:2011-07-06 18:00:57
【问题描述】:

一位同事告诉我他花了很多时间调试比赛条件。罪魁祸首竟然是这样的:

void foo()
{
    ScopedLock(this->mutex); // Oops, should have been a named object.
                             // Edit: added the "this->" to fix compilation issue.
    // ....
}

为了防止这种情况再次发生,他在定义ScopedLock类之后创建了如下宏:

#define ScopedLock(...) Error_You_should_create_a_named_object;

这个补丁运行良好。

有没有人知道任何其他有趣的技术来防止这个问题?

【问题讨论】:

  • “这个补丁运行良好”——直到你开始使用命名空间。
  • @Steve:只要您在另一个命名空间中没有任何名为 ScopedLock 的东西,它也可以在命名空间中正常工作。宏仍然可以使用命名空间限定(因为它无论如何都会产生错误)。
  • @Jeremiah:命名空间的唯一目的是允许您在另一个命名空间中拥有名为 ScopedLock 的东西。或者具体来说,编写代码以便您不在乎其他人是否喜欢他们的类(函数或全局变量)名称 ScopedLock 的外观。
  • @Steve:是的,这是真的,如果在另一个命名空间中有任何名为 ScopedLock 的东西,宏会中断。
  • 另见stackoverflow.com/questions/914861/…,它可能是重复的,也可能不是重复的。

标签: c++


【解决方案1】:

您应该使用静态代码分析器,例如Cppcheck。对于以下代码:

class a { };

void f() {
    a();
}

cppcheck 生成以下输出:

$ cppcheck test.cpp
Checking test.cpp...
[test.cpp:4]: (error) instance of "a" object destroyed immediately

还检测到多种其他常见的编码错误。

(我是 Cppcheck 的一个相当新的贡献者。几个月前我发现了它,使用它真是太棒了。)

【讨论】:

  • 谢谢。我已经对 Cppcheck 进行了几次试验,发现它很有用。也许我应该努力将它与我们的构建系统集成。
  • @StackedCrooked:Cppcheck 的开发速度非常快。如果您最近没有尝试过,一定要再试一次。
【解决方案2】:

如果你要定义一个宏,我可能宁愿定义这个:

#define GET_SCOPED_LOCK(name, mtx) ScopedLock name(mtx)

并停止通过宏创建对象。

如果有帮助,请将 ScopedLock 重命名为 ThisClassNameShouldNotAppearInUserCode

【讨论】:

  • 您可以使用宏中的“名称”。如果它是一个范围锁,您将不会在同一范围内有两个不同的对象,因此您可以使用“常量”名称而不必担心重复。
  • @Computer Guru:为了方便起见,您也可以随时提供。在我看来,在没有用户真正看到该名称是什么的情况下将名称引入作用域(文档中除外)似乎有点侵入性。只要对象不提供函数供用户调用,使用编译器生成的唯一名称就可以解决这个问题。同样有点尴尬的是,如果你想锁定两个互斥体,你必须引入大括号(并且可能处理编译器警告关于隐藏外部变量)。
猜你喜欢
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 2019-01-07
  • 2021-08-06
  • 2014-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多