C++11
Posted qnbk
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11相关的知识,希望对你有一定的参考价值。
C++11
同一列表初始化
初始化列表时,可以不添加等号
struct Point
int _x;
int _y;
;
int main()
Point p = 1, 2 ;
Point p 1, 2 ;//可以不使用 '='
int x2 2 ;
int* p = new int[4]0;
int* p1 = new int[4]1, 2, 3, 4;
return 0;
initializer_list
#include <iostream>
#include <initializer_list>
int main()
auto li = 10, 20, 30 ;
initializer_list<int> li2 = 1, 2, 3, 4 ;
cout << typeid(li).name() << endl;
return 0;
int main()
auto li = 10, 20, 30 ;
initializer_list<int> li2 = 1, 2, 3, 4 ;
cout << typeid(li).name() << endl;
vector<int> v = 1, 2, 3, 4, 5 ;
list<int> l 10, 20, 30 ;
//vector<Date> vd = 2001, 1, 1 , 2002, 2, 2 ;
map<string, int> dict = make_pair("sort", 1), "insert", 2 ;
return 0;
decltype
将变量的类型声明成指定的类型
int main()
int i = 10;
auto p = &i;
auto pf = strcpy;
cout << typeid(p).name() << endl;
cout << typeid(pf).name() << endl;
decltype(pf) px;
cout << typeid(px).name() << endl;
return 0;
//decltype的一些使用使用场景
template<class T1, class T2>
auto F(T1 t1, T2 t2) -> decltype(t1 * t2)//箭头指向返回值类型
decltype(t1 * t2) ret;
cout << typeid(ret).name() << endl;
return ret;
int main()
F(1, 2.2);
return 0;
右值引用
C++98中提出了引用的概念,引用即别名,引用变量与其引用实体公共同一块内存空间,而引用的底层是通过指针来实现的,因此使用引用,可以提高程序的可读性。
为了提高程序运行效率,C++11中引入了右值引用,右值引用也是别名,但其只能对右值引用。
左值与右值
可以放在=左边的,或者能够取地址的称为左值,只能放在=右边的,或者不能取地址的称为右值,但是也不一定完全正确。
右值eg:字面常量、表达式返回值,函数返回值等
- 1、普通类型的变量,因为有名字,可以取地址,都认为是左值。
- 2、 const修饰的常量,不可修改,只读类型的,理论应该按照右值对待,但因为其可以取地址(如果只是 const类型常量的定义,编译器不给其开辟空间,如果对该常量取地址时,编译器才为其开辟空间), C++11认为是左值。
- 3、 如果表达式的运行结果是一个临时变量或者对象,认为是右值。
- 4、 如果表达式运行结果或单个变量是一个引用则认为是左值。
总结:
- 不能简单地通过能否放在=左侧右侧或者取地址来判断左值或者右值,要根据表达式结果或变量的性质 判断
- 能得到引用的表达式一定能够作为引用,否则就用常引用。
int main()
double x = 1.1, y = 2.2;
// 以下几个都是常见的右值
10;
x + y;
fmin(x, y);
// 以下几个都是对右值的右值引用
int&& rr1 = 10;
double&& rr2 = x + y;
double&& rr3 = fmin(x, y);
cout << &rr1 << endl;
rr1 = 20;//没被存起来,因为是临时变量(右值不能取地址)
cout << &rr1 << endl;
// 这里编译会报错:error C2106: “=”: 左操作数必须为左值
//10 = 1;
//x + y = 1;
//fmin(x, y) = 1;
return 0;
引用与右值引用
普通引用只能引用左值,不能引用右值,const引用既可引用左值,也可引用右值。
C++11中右值引用:只能引用右值,一般情况不能直接引用左值。
右值不能取地址的,但是给右值取别名后,右值会被存储到特定的位置,且可以取到该位置的位置int main()
// 10纯右值,本来只是一个符号,没有具体的空间,
// 右值引用变量r1在定义过程中,编译器产生了一个临时变量,r1实际引用的是临时变量
int&& r1 = 10;
r1 = 100;
int a = 10;
int&& r2 = a; // 编译失败:右值引用不能引用左值
return 0;
// 1、左值引用 -》 左值
// 2、右值引用 -》 右值
// 3、const 左值引用 -》左值 或 右值
// 4、右值引用 -》 std::move(左值)
int main()
// 左值引用只能引用左值,不能引用右值。
int a = 10;
int& ra1 = a; // ra为a的别名
// int& ra2 = 10; // 编译失败,因为10是右值
const int& ra2 = 10;
const int& ra3 = 10 + 20;
return 0;
右值引用的场景和意义
namespace test
class string
public:
typedef char* iterator;
iterator begin()
return _str;
iterator end()
return _str + _size;
string(const char* str = "")
:_size(strlen(str))
, _capacity(_size)
//cout << "string(char* str)" << endl;
_str = new char[_capacity + 1];
strcpy(_str, str);
// s1.swap(s2)
void swap(string& s)
::swap(_str, s._str);
::swap(_size, s._size);
::swap(_capacity, s._capacity);
// 拷贝构造
string(const string& s)
:_str(nullptr)
cout << "string(const string& s) -- 深拷贝" << endl;
string tmp(s._str);
swap(tmp);
// 赋值重载
string& operator=(const string& s)
cout << "string& operator=(string s) -- 深拷贝" << endl;
string tmp(s);
swap(tmp);
return *this;
~string()
delete[] _str;
_str = nullptr;
char& operator[](size_t pos)
assert(pos < _size);
return _str[pos];
void reserve(size_t n)
if (n > _capacity)
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
void push_back(char ch)
if (_size >= _capacity)
size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
reserve(newcapacity);
_str[_size] = ch;
++_size;
_str[_size] = '\\0';
//string operator+=(char ch)
string& operator+=(char ch)
push_back(ch);
return *this;
const char* c_str() const
return _str;
private:
char* _str;
size_t _size;
size_t _capacity; // 不包含最后做标识的\\0
;
test::string to_string(int value)
bool flag = true;
if (value < 0)
flag = false;
value = 0 - value;
test::string str;
while (value > 0)
int x = value % 10;
value /= 10;
str += ('0' + x);//尾插
if (flag == false)
str += '-';
std::reverse(str.begin(), str.end());
return str;//编译器把str识别成一个右值
//
// 左值引用的使用场景
// 1、做参数 -- 可以
// 2、做返回值 -- 有缺陷
void func1(test::string s)
void func2(const test::string& s)
int main()
test::string s1("hello world");
// func1和func2的调用我们可以看到左值引用做参数减少了拷贝,提高效率的使用场景和价值
//func1(s1);
func2(s1);
// operator+=可以使用传左值引用返回
s1 += 'A';
// to_string 不能用左值引用返回,这个就是左值引用短板
// 如果函数返回对象除了函数作用域就不在了,就不能使用做引用返回,就会存在拷贝
test::string ret1 = test::to_string(1234);
test::to_string(1234);
return 0;
左值引用的短板:当函数返回对象是一个局部变量,出了函数作用域就不存在了,就不能使用左值引用返回,只能传值返回。eg:test::to_string(int value) 这里只能传值返回,传值返回会导致至少1次拷贝构造(旧编译器是2次)
右值引用和移动语义解决以上问题: 移动构造本质是将参数右值的资源窃取过来占为己有,不需要深拷贝,所以叫移动构造,就是窃取别人资源来构造自己(没有开新空间拷贝数据,效率提高)
// 移动构造 增加一个参数是右值引用的版本
string(string&& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
//转移资源
cout << "string(string&& s) -- 移动构造" << endl;
this->swap(s);
// 移动赋值
string& operator=(string&& s)
cout << "string& operator=(string&& s) -- 移动赋值" << endl;
this->swap(s);
return *this;
namespace test
class string
public:
typedef char* iterator;
iterator begin()
return _str;
iterator end()
return _str + _size;
string(const char* str = "")
:_size(strlen(str))
, _capacity(_size)
//cout << "string(char* str)" << endl;
_str = new char[_capacity + 1];
strcpy(_str, str);
// s1.swap(s2)
void swap(string& s)
::swap(_str, s._str);
::swap(_size, s._size);
::swap(_capacity, s._capacity);
// 拷贝构造
string(const string& s)
:_str(nullptr)
cout << "string(const string& s) -- 深拷贝" << endl;
string tmp(s._str);
swap(tmp);
// 移动构造 增加一个参数是右值引用的版本
string(string&& s)
:_str(nullptr)
, _size(0)
, _capacity(0)
//转移资源
cout << "string(string&& s) -- 移动构造" << endl;
this->swap(s);
// 移动赋值
string& operator=(string&& s)
cout << "string& operator=(string&& s) -- 移动赋值" << endl;
this->swap(s);
return *this;
// 赋值重载
string& operator=(const string& s)
cout << "string& operator=(string s) -- 深拷贝" << endl;
string tmp(s);
swap(tmp);
return *this;
~string()
delete[] _str;
_str = nullptr;
char& operator[](size_t pos)
assert(pos < _size);
return _str[pos];
void reserve(size_t n)
if (n > _capacity)
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
void push_back(char ch)
if (_size >= _capacity)
size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
reserve(newcapacity);
_str[_size] = ch;
++_size;
_str[_size] = '\\0';
//string operator+=(char ch)
string& operator+=(char ch)
push_back(ch);
return *this;
const char* c_str() const
return _str;
private:
char* _str;
size_t _size;
size_t _capacity; // 不包含最后做标识的\\0
;
test::string to_string(int value)
bool flag = true;
if (value < 0)
flag = false;
value = 0 - value;
test::string str;
while (value > 0)
int x = value % 10;
value /= 10;
str += ('0' + x);//尾插
if (flag == false)
str += '-';
std::reverse(str.begin(), str.end());
return str;//编译器把str识别成一个右值
//使编译器优化,两次移动构造合二为一
2021.11.6-测试