我有一个 ScopedLock
当超出范围时,可以帮助自动释放锁的类。
但问题是:有时团队成员会编写无效的锁码,例如
{
ScopedLock(mutex); // anonymous
xxx;
}
上面的代码是错误的,因为 ScopedLock
对象被构造和破坏 立即,因此无法锁定预期区域(xxx
)。我希望编译器在尝试编译此类代码时发出错误。可以这样做吗?
我搜索过了 g++
警告选项,但找不到合适的选项。
我有一个 ScopedLock
当超出范围时,可以帮助自动释放锁的类。
但问题是:有时团队成员会编写无效的锁码,例如
{
ScopedLock(mutex); // anonymous
xxx;
}
上面的代码是错误的,因为 ScopedLock
对象被构造和破坏 立即,因此无法锁定预期区域(xxx
)。我希望编译器在尝试编译此类代码时发出错误。可以这样做吗?
我搜索过了 g++
警告选项,但找不到合适的选项。
为避免这种情况,请引入一个为您执行此操作的宏,始终使用与锁定器相同的名称:
#define LOCK(mutex) ScopedLock _lock(mutex)
然后像这样使用它:
{
LOCK(mutex);
xxx;
}
作为替代,Java的 synchronize
可以使用宏构造模拟块:在for循环运行中总是只运行一次,我在for循环的初始化语句中实例化这样一个锁定器,因此在离开for循环时它会被破坏。
然而,它有一些陷阱,一个意想不到的行为 break
声明就是一个例子。这个“黑客”被引入 这里。
当然,上述方法都没有像你的例子那样完全避免意外代码。但是,如果您习惯使用两个宏中的一个来编写锁定互斥锁,则不太可能发生。因为除了宏定义之外,锁定器类的名称将永远不会出现在代码中,您甚至可以在版本控制系统中引入提交挂钩以避免提交无效代码。
我在一个代码库中看到了一个有趣的技巧,但只有当你的scoped_lock类型不是模板时才有效(std :: scoped_lock是)。
#define scoped_lock(x) static_assert(false, "you forgot the variable name")
如果您正确使用该类,则可以
scoped_lock lock(mutex);
并且由于scoped_lock标识符后面没有打开的paren,宏不会触发,代码将保持原样。如果你写
scoped_lock(mutex);
宏将触发,代码将被替换
static_assert(false, "you forgot the variable name");
这将生成信息性消息。
如果您使用限定名称
threads::scoped_lock(mutext);
然后结果仍然无法编译,但消息不会那么好。
当然,如果您的锁是模板,那么错误的代码就是
scoped_lock<mutex_type>(mutex);
这不会触发宏。
不,不幸的是 没有办法做到这一点, 正如我去年在博客中探讨过的那样。
在其中,我得出结论:
我想这个故事的寓意是要记住 这个 使用时的故事
scoped_lock
秒。
您可以尝试强制团队中的所有程序员使用宏或范围换技巧,但如果您可以保证在每种情况下都可以保证在每种情况下都能捕获此错误。
你正在寻找一种方法 编程 当它被制作时捕捉到这个特定的错误,并且没有。
您可以使用具有相同名称的类和已删除的函数。不幸的是,这需要在类型之前添加“class”关键字。
class Guard
{
public:
explicit Guard(void)
{
}
};
static void Guard(void) = delete;
int main()
{
// Guard(); // Won't compile
// Guard g; // Won't compile
class Guard g;
}
AFAIK在gcc中没有这样的旗帜。静态分析仪可能更适合您的需求。
用宏替换它
#define CON2(x,y) x##y
#define CON(x,y) CON2(x,y)
#define LOCK(x) ScopedLock CON(unique_,__COUNTER__)(mutex)
用法
{
LOCK(mutex);
//do stuff
}
此宏将为锁生成唯一的名称,允许锁定内部作用域中的其他互斥锁