C++11的问题若干
历史遗留问题
被弃用的特性
- 如果一个类有析构函数,为其生成拷贝构造函数和拷贝赋值运算符的特性被弃用了。
不再允许字符串字面值常量赋值给一个
char *
。如果需要用字符串字面值常量赋值和初始化一个char *
,应该使用const char *
或者auto
。 e.g.1
char *str = "hello world!"; // 将出现弃用警告
C++98 异常说明、 unexcepted_handler、set_unexpected() 等相关特性被弃用,应该使用 noexcept。
- auto_ptr 被弃用,应使用 unique_ptr。
- register 关键字被弃用。
- bool 类型的 ++ 操作被弃用。
- C 语言风格的类型转换被弃用,应该使用。
static_cast
、reinterpret_cast
、const_cast
来进行类型转换。 - 还有一些其他诸如参数绑定(C++11 提供了 std::bind 和 std::function)、export 等特性也均被弃用。
C++ 不是 C 的一个超集
在编写 C++ 时,也应该尽可能的避免使用诸如 void* 之类的程序风格。而在不得不使用 C 时,应该注意使用 extern “C” 这种特性,将 C 语言的代码与 C++代码进行分离编译,再统一链接这种做法。 e.g.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22// foo.h
extern "C" {
int add(int x, int y);
}
// foo.c
int add(int x, int y) {
return x+y;
}
// main.cpp
int main() {
add(1, 2);
return 0;
}
要先编译c代码, 然后再把c++和.o代码链接起来1
2gcc -c foo.c
g++ main.cpp foo.o -o main
语言特性增强
nullptr and constexpr
nullptr
nullptr
出现的目的是为了替代NULL
。在某种意义上来说,传统C++
会把NULL
、0
视为同一种东西,这取决于编译器如何定义NULL
,有些编译器会将NULL
定义为((void*)0)
,有些则会直接将其定义为0
。C++
不允许直接将void *
隐式转换到其他类型C++11
引入了nullptr
关键字,专门用来区分空指针
、0
。nullptr
的类型为nullptr_t
,能够隐式的转换为任何指针或成员指针的类型,也能和他们进行相等或者不等的比较。 防止NULL转换撑0, 进而在重载过程中匹配成int
constexpr
1 | #define LEN 10 |
在 C++11
之前,可以在常量表达式中使用的变量必须被声明为 const
,在上面代码中,len_2
被定义成了常量,因此 len+5
是一个常量表达式,所以能够合法的分配一个数组;
而对于 arr_5
来说,C++98
之前的编译器无法得知 len_foo()
在运行期实际上是返回一个常数,这也就导致了非法的产生。C++11
提供了 constexpr
让用户显式的声明函数或对象构造函数在编译器会成为常数,这个关键字明确的告诉编译器应该去验证 len_foo
在编译器就应该是一个常数。也就是说, 相当于函数返回的值告诉编译器也是一个const, 可作为数组的长度定义。
同时constexpr的函数还支持递归, e.g.1
2
3constexpr int fibonacci(const int n) {
return n == 1 || n == 2 ? 1 : fibonacci(n-1)+fibonacci(n-2);
}
Deduction
auto
auto
在很早以前就已经进入了 C++
,但始终作为一个存储类型的指示符存在,与 register 并存。在传统 C++
中,如果一个变量没有声明为 register,将自动被视为一个 auto。然而register 被弃了,auto 的语义变更也就非常自然了。
常见用法
1 | auto i = 5; // i 被推导为 int |
但是, auto 不能用于函数传参,因此下面的做法是无法通过编译的(考虑重载的问题,我们应该使用模板); 此外,auto 还不能用于推导数组类型
auto应用于迭代器
三者遍历方式等价, 只是最后一种auto的是元素本身类型, 不是迭代器本身1
2
3
4
5for(vector<int>::const_iterator itr = vec.cbegin(); itr != vec.cend(); ++itr)
for(auto itr = vec.cbegin(); itr != vec.cend(); ++itr);
for(auto item: vec)
decltype
decltype
关键字是为了解决 auto
关键字只能对变量进行类型推导的缺陷而出现的, 用法类似sizeof
. e.g.计算某个表达式的类型:1
2
3auto x = 1;
auto y = 2;
decltype(x+y) z;