我有一个ScopedLock
类,可以帮助在超出范围时自动释放锁定。
但问题是:有时团队成员会编写无效的锁码,例如
{
ScopedLock(mutex); // anonymous
xxx;
}
上面的代码是错误的,因为ScopedLock
对象是立即构建和销毁,因此无法锁定预期区域(xxx
)。我希望编译器在尝试编译此类代码时出错。可以这样做吗?
我搜索了g++
个警告选项,但找不到合适的警告选项。
答案 0 :(得分:7)
我在一个代码库中看到了一个有趣的技巧,但它只有在你的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);
不会触发宏。
答案 1 :(得分:5)
不,不幸的是无法做到这一点,as I explored in a blog post last year。
在其中,我总结道:
我想这个故事的寓意是在使用
scoped_lock
时记住这个的故事。
您可以尝试强制团队中的所有程序员使用宏或范围换技巧,但如果您能保证在每种情况下都可以保证在每种情况下都能捕获此错误
您正在寻找一种以编程方式捕获此特定错误的方法,并且没有。
答案 2 :(得分:2)
为了避免这种情况,请引入一个为您执行此操作的宏,始终使用与锁定器相同的名称:
#define LOCK(mutex) ScopedLock _lock(mutex)
然后像这样使用它:
{
LOCK(mutex);
xxx;
}
作为替代方案,Java的synchronize
块可以使用宏构造进行模拟:在for循环运行中始终只运行一次,我在for循环的初始化语句中实例化这样一个锁定器,因此它得到离开for-loop时被摧毁。
然而,它有一些陷阱,break
语句的意外行为就是一个例子。这个“黑客”被引入here。
当然,上述方法都没有像你的例子那样完全避免意外的代码。但是,如果您习惯使用两个宏中的一个编写锁定互斥锁,则不太可能发生。因为除了宏定义之外,锁定器类的名称将永远不会出现在代码中,您甚至可以在版本控制系统中引入提交钩子以避免提交无效代码。
答案 3 :(得分:2)
您可以使用具有相同名称的类和已删除的函数。不幸的是,这需要添加&#34; class&#34;类型前的关键字。
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;
}
答案 4 :(得分:1)
AFAIK在gcc中没有这样的旗帜。静态分析仪可能更适合您的需求。
答案 5 :(得分:0)
将其替换为宏
#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
}
此宏将为锁生成唯一的名称,允许锁定内部作用域中的其他互斥锁
答案 6 :(得分:0)
在C ++ 17中,可以将类型标记为[[nodiscard]]
,在这种情况下,鼓励对丢弃该类型的值的表达式进行警告(包括此处所述的类似于a的声明的情况)变量)。在C ++ 20中,如果只有一部分构造函数会导致这种问题,那么它也可以应用于单个构造函数。