THUOOP
THUOOP copied to clipboard
auto,auto& 与auto*
auto, auto* 与 auto&
by 刘泓尊 计84 [email protected]
c++98 auto
c++98标准中设置了auto
关键字,与c++11的auto
存在很大不同。c++98的auto
用于声明变量为自动变量,拥有自动的生命周期。
int a =1; //拥有自动生命期
auto int b = 2; //拥有自动生命期
static int c = 3; //延长了生命期
C++98中的auto
多余且极少使用,c++11中auto
已经改为了“自动推断变量的类型”。
c++11 auto
1. 为变量自动选择匹配的类型
auto i = 100; //int
auto p = new MyClass(); // MyClass*
auto a = 123LL; //long long
但是上述做法也带来了缺陷,那就是降低了代码的可读性。
但还存在一个权衡:当在单独的较小的代码区域内重复类名时,重复可能无助于提高可读性。
2. 代替冗长却又没必要写明的变量类型
std::vector<std::string> vec;
for(auto iter = vec.begin(); iter != vec.end(); iter ++){
//do something...
}
在这里,auto
代替了std::vector<std::string>::iterator
上述循环在c++11中还可以简化为基于范围的for循环:
for(auto iter : vec){
//do something...
}
! ! ! 尤其是遍历/使用map时,特别推荐使用auto。
因为很多人可能不知道map
的value_type是std::pair<const KeyType, MappedType>
而不是std::pair<KeyType, MappedType>
,但是当你用后者时,编译是能通过的,因为存在隐式构造类型转换。但是转换后的对象就不再是map
中存的那个。
for (const auto& item : some_map) {
const KeyType& key = item.first;
const ValType& value = item.second;
// The rest of the loop can now just refer to key and value, a reader can see the types in question, and we've avoided the too-common case of extra copies in this iteration.
}
3. 用于声明依赖于模板参数的变量类型
template<class Tx, class Ty>
auto add(Tx x, Ty y) -> decltype(x + y){ //c++11
return x + y;
}
template<class Tx, class Ty>
auto add(Tx x, Ty y){ //c++14
return x + y;
}
4. 配合lambda表达式
如果不使用auto
, 那么一般需要使用std::function
来存储。
auto closure = [](const int&, const int&){} //{lambda(int const&, int const&)#1}
auto closure = [](auto x, auto y){return x + y;} //c++14
//Sort `vec` in increasing order
std::sort(vec.begin(), vec.end(), [](auto lhs, auto rhs){
return lhs > rhs;
}));
5. 常见错误汇总
a. auto变量必须在定义时初始化
b. 对于多个auto变量的定义,这些变量必须为同一类型
auto a = 1, b = 2, c = 3; //correct
auto a = 1, b = "123"; //error: inconsistent deduction for 'auto': 'int' and then 'const char*'
c. auto初始化表达式是引用&时, 去除引用语义
int a = 1;
int &b = a;
auto c = b; //此时c的类型是int,不是int&
如果想令c
的类型是引用,必须显式声明为auto&
类型
auto& c = b;//此时c的类型是int&
d. 初始化表达式若为const/ volatile, 则去除const/ volatile(CV-qualifiers)语义
如有需要,则需要显式声明为const auto
类型。
const int a = 10;
auto b = a; //b的类型为int,而不是const int
const auto c = a; //c的类型才为const int
注意:若auto
关键字显式加上&符号,则不去除const
语义
const int a = 10;
auto& d = a; //d的类型为const int
e. auto初始化表达式右值为数组时,auto推导为指针类型;auto&推导为数组类型。
int a[5] = {1, 2, 3, 4, 5};
auto b = a; //b类型为int*
auto &c = a; //c类型为int [5]
注意,指针≠数组。
实际上,根据issue11[https://github.com/thu-coai/THUOOP/issues/11]中王世麟同学的分析,除以下三种情况,其他情况下数组都会退化成指向首元素的指针:
1. sizeof(s)
2. &s
3. "123"本身作为数组不退化
参考资料
《Google C++ Style Guide》,http://google.github.io/styleguide/cppguide.html
5.c中 auto*有类似表现 能够解释下吗
update:
f. 对于加了代理(proxy)的对象,auto可能无法得到你想要的类型
std::vector<bool> vec_bool;
std::vector<int> vec_int;
vec_bool.push_back(false);
vec_int.push_back(0);
auto abool = vec_bool[0]; //std::_Bit_reference
auto aint = vec_int[0]; //int
auto temp = static_cast<bool>(abool);//bool
上例中,vector<bool>
实际上加了一层代理类_Bit_reference
。因为vector< bool>里面不是一个Byte一个Byte储存的,它是一个bit一个bit储存的。
可以通过static_cast<bool>
来转换为bool类型。
g. auto* 的表现
auto*
的表现比auto&
情况简单很多,基本可以认为,如果赋值右侧为指针对象,那么左侧auto
与 auto*
无异。
int* arr_ptr1 = new int[5];
auto arr_ptr2 = arr_ptr1; //int*
auto* arr_ptr3 = arr_ptr1;//int*
int *ptr_arr[10]; //指针数组
auto ptr_arr1 = ptr_arr; //int**
int (*arr_ptr)[10]; //数组指针
auto arr_ptr_copy = arr_ptr;//int (*)[10]
int* int_ptr1 = new int(10);
auto int_ptr2 = int_ptr1; //int*
auto int_ptr3 = int_ptr2; //int*
auto* int_ptr4 = int_ptr2;//int*
int var = 10;
auto var_ptr1 = &var; //int*
auto var_ptr2 = var_ptr1; //int*
auto* var_ptr3 = var_ptr1; //int*
h.关于字符串的类型推导
auto str1 = "123"; //char const*
auto& str2 = "123"; //char [4]
auto* str3 = "123"; //char const*
因为str1
与str3
是指针,自然也就不能使用基于范围的for循环了。