c++11 特性
C++11标准是 ISO/IEC 14882:2011 - Information technology – Programming languages – C++ 的简称。 C++11标准由国际标准化组织(ISO)和国际电工委员会(IEC)旗下的C++标准委员会(ISO/IEC JTC1/SC22/WG21)于2011年8月12日公布,并于2011年9月出版。2012年2月28日的国际标准草案(N3376)是最接近于C++11标准的草案(仅编辑上的修正)。此次标准为C++98发布后13年来第一次重大修正。
官方链接 https://en.cppreference.com/w/cpp/11
c++11 特性
1. 自动类型推导 auto & decltype
// 自动类型推导
std::map<std::string, std::string> m;
auto it = m.find("hello");
// decltype
auto i = 0;
decltype(i * 1.0) j; // typeid(j).name(): d
2. 左值,右值,移动语义,完美转发
- 左值:带地址的值,可访问
- 右值:
- 纯右值:寄存器值,常量等不含内存地址的值
- 将亡值:内存地址不可见的值,如函数返回值临时变量
- RVO 返回值优化
- 函数返回本地结构体变量等复杂数据,此时赋值会涉及多次拷贝
- 返回值优化可以替换本地变量地址为外部地址,实现无拷贝赋值
class A {
std::string _name;
public:
A() {
std::cout << "construct 0" << std::endl;
}
explicit A(const std::string& name) {
std::cout << "construct 1" << std::endl;
_name = name;
}
A(const A& a) {
std::cout << "copy construct" << std::endl;
_name = a._name;
}
A& operator=(const A& a) {
std::cout << "operator =" << std::endl;
_name = a._name;
return *this;
}
};
A getA(const std::string& name) {
A a(name);
std::cout << &a << std::endl;
return a; // 返回本地变量
}
int main() {
// 编译选项: -fno-elide-constructors
// 将亡值赋值,一次构造,两次拷贝
A a = getA("456");
std::cout << &a << std::endl;
// 引用强行续命, 一次构造一次拷贝
const A& b = getA("123");
std::cout << &b << std::endl;
// 去除编译选项
// 返回值优化,仅一次构造
A a = getA("456");
std::cout << &a << std::endl;
}
- 移动语义 std:move()
- 通过重载右值引用版本实现移动操作,减少内存复制
class B {
char* buf{};
int size{};
public:
B() = delete;
explicit B(int size) : size(size) {
buf = new char[size];
}
B(const B& b) {
std::cout << "copy" << std::endl;
size = b.size;
buf = new char[b.size];
memcpy(buf, b.buf, b.size);
}
// 移动构造,无需分配新空间
B(B&& b) noexcept {
std::cout << "move" << std::endl;
size = b.size;
buf = b.buf;
b.size = 0;
b.buf = nullptr;
}
B& operator=(const B& b) {
std::cout << "=copy" << std::endl;
if (&b == this) {
return *this;
}
// clear
delete []buf;
size = b.size;
buf = new char[b.size];
memcpy(buf, b.buf, b.size);
return *this;
}
// 移动赋值, 直接复制指针
B& operator=(B&& b) noexcept {
std::cout << "=move" << std::endl;
if (&b == this) {
return *this;
}
this->buf = b.buf;
this->size = b.size;
b.size = 0;
b.buf = nullptr;
return *this;
}
~B() {
delete []buf;
}
int len() const {
return size;
}
};
int main() {
B x(5);
B y = x; // copy
B z = std::move(x); // move
B xx(6);
y = xx; // =copy
z = std::move(xx); // =move
z = B(8); // =move
B zz(B(10)); // move
return 0;
}
- 完美转发 std::forward()
- 右值引用传入函数为左值,下游调用若需要右值,需要完美转发
template<typename T>
void lr_test(T&) {
std::cout << "lvalue" << std::endl;
}
template<typename T>
void lr_test(T&&) {
std::cout << "rvalue" << std::endl;
}
template<typename T>
void lr_normal(T&& a) {
// 分配栈空间给a, 此时a 是语义右值,实质左值
lr_test(a); // 直接调用,传入左值
}
template<typename T>
void lr_normal(T& a) {
lr_test(a);
}
template<typename T>
void lr_forward(T&& t) {
lr_test(std::forward<T>(t));
}
int main() {
int i = 0;
lr_normal(1); //rvalue -> lvalue
lr_normal(i); // lvalue
lr_forward(1); // rvalue
lr_forward(i); // lvalue
}
3. 列表初始化
auto l = {"a", "b", "c"};
for (const auto& item : l) {
std::cout << item << std::endl;
}
4. std::function 与 lambda表达式
- std::bind, 绑定参数, 生成新的std::function
// placeholders::_x 参数占位符
auto minus = [](int i, int j) ->int {return i-j;};
auto minus_by_five = std::bind(minus, 5, std::placeholders::_1);
auto minus_eight = std::bind(minus, std::placeholders::_1, 8);
std::cout << minus_by_five(10) << std::endl;
std::cout << minus_eight(16) << std::endl;
// bind object,函数地址, 对象地址
auto f = std::bind(&B::len, &zz);
std::cout << f() << std::endl;
- lambda
// base function, lambda
std::function<void()> f = []() {/* statments */}
- 变量捕获: 值捕获, 引用捕获
auto o = 0;
auto n = 1;
auto fx = [o, &n]() {
n = 100; // change
return o; // readonly
};
std::cout << n << "," << o << std::endl;
std::cout << fx() << std::endl;
std::cout << n << "," << o << std::endl;
5. template 优化 » 问题
// >> 模版参数优化
std::map<std::string, std::list<std::string>> list; // invalid before c++11
6. 并发支持
- std::thread 线程
- std::mutex 互斥量
- std::atomic 原子变量
- std::condition 条件变量
- std::future
- std::async
- std::promise
- std::packaged_task
7. for range 循环
auto l = {1,2,3};
for (const auto&i : l) {
// do something with i
}
8. 委托构造
class A{
std::string _name;
public:
explicit A(const std::string& name) : _name(name) {}
}
class B:public A {
// 子类委托父类构造
explicit B(const std::string& name) :A(name) {}
}
9. nullptr 与 nullptr_t
char* buf = NULL; // before c++11
char* buf = nullptr; // after c++11
10. final, override 关键字
- final 类禁止继承, final 方法禁止重写
- override 重写 virtual方法
class C final {}; // can not extend
class D {
public:
virtual void say() {}
virtual void play() final {} // cannot override
};
class E: public D {
void say() override {} // override
// void play() override {} // error
};
11. explicit 构造禁止隐式转换
- 建议使用 explicit 修饰单参数构造函数避免隐式转换
class F {
int data;
public:
F(int d) : data(d) {}
};
class G {
int data;
public:
explicit G(int d) : data(d) {}
};
int main() {
F f(1);
G g(1);
F f2 = 1; //ok
// G g2 = 1; //nok
return 0;
}
12. const, constexpr编译期常量
- const 修饰变量为不可变变量(仅修饰作用,一些原本可变更的可用通过类型转换改变其值
- constexpr: 编译期便确定的常量,编译阶段可以使用,运行期不可变
13. enum class
- 强类型enum
14. union POD 扩展
- union 不仅支持POD, 也支持普通对象了
15. sizeof(class::member)
- sizeof 操作符支持查看对象成员的大小
16. static_assert 编译期断言
- 编译期断言,断言失败编译失败
17. 自定义字面量
- 通过 operator"" 自定义含unsigned long long 的字面量
constexpr mytype operator"" _mytype(uint64_t i) {
return mytype(i);
}
18. 内存对齐
- alignof
- alignas
19. thread_local 线程变量
- thread_local 修饰的变量为线程内部变量,每个线程有自己的拷贝
20. 数据类型 long long, char16_t, char32_t
- 新增数据类型 long long, char16_t, char32_t
21. 随机数
std::random
22. 正则表达式
- std:regex, 支持常用正则表达式, 有一些特性不支持
23. chrono
std::chrono::duration 时间段 std::chrono::time_point 时间点 std::chrono::steady_clock 时钟 std::chrono::system_clock 时钟
24. 容器
- std::array 固定大小的数组,支持越界检查
- std::tuple 元组, std::pair 的扩展
- std::unordered_set 无序集合, hash表
- std::unordered_map 无序映射, hash表
25. 算法
- all_of
- any_of
- none_of
- find_if
- …
26. 智能指针
- std::shared_ptr
- std::unique_ptr
- std::weak_ptr