我正在读一本书,它有一个使用 RAII 习语处理流的类的示例。这是代码
class thread_guard {
thread& t;
public:
explicit thread_guard(thread& _t) : t(_t){}
~thread_guard() {
if (t.joinable())
t.join();
}
thread_guard(thread_guard const&) = delete;
thread_guard& operator=(thread_guard const&) = delete;
};
void f(int i, std::string const& s) {
cout << s << " " << i << endl;
}
int main(int argc, char* argv[]){
thread thr1(f, 2, "test");
thread_guard{ thr1 };
}
我的问题是如果在一个函数int main
中包含该操作就行
thread_guard{ thr1 };
使用括号而不是花括号,代码将无法编译。我无法弄清楚它们目前有何不同。斯科特迈尔斯没有写关于它
每当 C++ 语言中的声明和表达式之间存在歧义时- 即 在构造既可以是语法正确的声明又可以是语法正确的表达式的情况下,语言必须将构造视为声明。
根据这个规则,变体
thread_guard( thr1 );
是一个变量声明thr1
,变量名周围有额外的括号。声明语法不禁止这样的括号如果您愿意,您可以像这样故意“搞乱”声明语法
或者
并且编译器将被迫将此代码解释为表达式,即 它将变得等同于带有
{}
.实际上,通过 just 进行统一初始化的美妙之
{}
处主要在于没有这种歧义。我对 GCC 在这个版本中的行为感到惊讶
GCC 拒绝编译它,而 Clang 也接受这个选项作为表达式。
如果我没记错的话
编译器将其视为
thr1
类型变量的声明thread_guard
,并且此类变量上方的行已经以不同方式声明。现在,如果你写,说,通过显式指定一个变量,它将是一个
tg
已初始化变量的声明thr1
,并且代码将安静地工作。使用花括号,除了初始化之外,您无法阅读此内容,并且代码是创建
thread_guard
使用 reference 初始化的类型的 [未命名] 对象thr1
。“我想是的”(c)维尼