if-init
C++17新增,变量可以在if条件表达式内初始化,
int p = do_something();
if(p){
}
if(int p = do_something(); p){
}
- 如果你的变量p仅仅在if范围内使用,那么就可以使用if-init。这样做的好处就是控制了p的生命周期和作用域,一旦离开if语句,p立刻销毁,提高了一点效率,而且你可以在下面的代码中再次定义变量p,不会引起冲突。
- p的作用域是整个if语句,
if(p = do_something(); p) {
}
else if(q = do_other(); q){
}
else{
}
if-init可用的另外一个地方就是锁(lock),
static Singleton* GetInstance(){
if(_instance == nullptr){
{
unique_lock<mutex> lck(_mut);
if(_instance == nullptr)
_instance = new Singleton;
}
}
return _instance;
}
- 上面是单例模式获得对象的静态函数,其他部分我已省略。
- 可以看到在注释行多出一对大括号,这是C++17之前的手法,利用作用域限制锁的生命周期。否则就会扩大锁的范围,浪费资源。
- C++17之后我们可以利用if-init,这两个写法等价。
static Singleton* GetInstance(){
if(_instance == nullptr){
if(unique_lock<mutex> lck(_mut); _instance == nullptr)
_instance = new Singleton;
}
return _instance;
}
- 可以看到代码简洁不少。if-int和下面要介绍的结构体绑定也有联动。
- switch语句也有同样的switch-int方式。使用方法和if相同,不再演示。
Structured Bindings
- C++17引入结构体绑定。你可能使用过C++11引入的tuple。
std::tuple<std::string, int> create_person(){
return {"zzh", 20};
}
std::tuple<std::string, int> my = create_person();
std::string& name = std::get<0>(my);
int& age = std::get<1>(my);
std::string name;
int age;
std::tie(name, age) = my;
- 但是,这两种方法都不太好。让我们看看结构体绑定的做法。
auto[name, age] = create_person();
- 必须使用auto。
- 不必像tie一样为每个对象单独声明。
- 还可以使用const auto, auto&等等。
- 结构体底层实际上就是通过get函数实现的。
auto __temp = create_person();
auto& name = std::get<0>(__temp);
auto& age = std::get<1>(__temp);
- 先拷贝一份__temp,然后去调用get函数。其中name和age是引用。
- 因为结构体绑定中我们使用auto,所以推导__temp也使用auto。
struct X {
int a_ = 0;
};
int main() {
auto [value1] = X();
auto& [value2] = X();
const auto [value3] = X();
return 0;
}
- 从上面我们可以看到,我们自己写的类也可以用于结构体绑定。这应该是正常的,因为tuple没有什么特殊的地方,毕竟tuple也不是语言特性。
- 结构体绑定使用的条件是什么呢?
- 这里简单介绍几点:
- 类所有成员变量为public;
- 如果类成员变量为private。那么你需要为该类提供get成员函数或者一个全局范围内的get函数,且你需要在std(没错,在std中)为你的类型提供特化版本的tuple_size, tuple_element。
std::tuple, std::array, std::pair。
int arr[4] = { 1, 2, 3, 4 };
auto [a, b, c, d] = arr;
std::array<int, 3> arrayObj{ 1, 2, 3 };
auto [e, f, g] = arrayObj;
std::pair<int, std::string> node(1, "zzh");
auto [age, name] = node;
for (std::map<int, std::string> countMap{ {20, "zzh"}, {24, "张三"} }; auto [age, name] : countMap) {
cout << age << "--" << name << endl;
}
|