网站的分页效果怎么做,什么是搜索引擎?,网站与网址的区别,佛山新网站建设服务目录
1、C11简介
2、列表的初始化
2.1 {}初始化
2.2 initializer_list
3、auto与decltype
3.1 auto
3.2 decltype
4、范围for循环
5、右值引用和移动语义
4.1 左值引用和右值引用
4.1.1 左值引用
4.1.2 右值引用
4.2 右值引用使用场景和意义 1、C11简介 C11是C语言…目录
1、C11简介
2、列表的初始化
2.1 {}初始化
2.2 initializer_list
3、auto与decltype
3.1 auto
3.2 decltype
4、范围for循环
5、右值引用和移动语义
4.1 左值引用和右值引用
4.1.1 左值引用
4.1.2 右值引用
4.2 右值引用使用场景和意义 1、C11简介 C11是C语言的一个重要版本于2011年发布。它引入了许多新特性和改进以提高C语言的表达能力、可移植性和性能。相比于 C98/03C11则带来了数量可观的变化其中包含了约140个新特性以及对C03标准中 约600个缺陷的修正这使得C11更像是从C98/03中孕育出的一种新语言。相比较而言 C11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全不仅功能更强大而且能提升程序员的开发效率。
2、列表的初始化
2.1 {}初始化
C98允许{}对数组和结构体元素进行初始化
//在C98中标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。
struct A
{int a 0;int b 0;
};
int main()
{int a[] { 1,2,3,4,5,6 };A a{ 1,2 };return 0;
} C11扩大了用大括号括起的列表(初始化列表)的使用范围使其可用于所有的内置类型和用户自 定义的类型使用初始化列表时可添加等号()也可不添加。
//在C11中扩大了用大括号括起的列表(初始化列表)的使用范围
// 使其可用于所有的内置类型和用户自定义的类型
//使用初始化列表时可添加等号( )也可不添加。templateclass T
struct A
{T a;T b;
};int main()
{Aint a{1,2};int b{ 0 };return 0;
}
并且适用于new表达式的初始化 创建对象时也可以使用列表初始化方式调用构造函数初始化 //创建对象时也可以使用列表初始化方式调用构造函数初始化
templateclass T
class Example
{
public:Example(T a,T b):_a(a),_b(b){}
private:int _a;int _b;
};
int main()
{Exampleint a{ 1,2 };Exampledouble a{ 1.2,2.5 };return 0;
} 2.2 initializer_list 此类型用于访问 C 初始化列表中的值该列表是 const T 类型的元素列表。此类型的对象由编译器根据初始化列表声明自动构造该声明是用大括号括起来的逗号分隔元素的列表。 std::initializer_list 一般是作为构造函数的参数 C11对STL 中的不少容器就增std::initializer_list作为参数的构造函数。 这样初始化容器对象就更方便了。也可以作为 operator 的参数这样就可以用大括号赋值 在list中就增加了initializer_list的构造 vectormap中同样增加了initializer_list构造 map 我们之前模拟实现过vector,那么我们可以尝试为vector加上initializer_list构造 vector(initializer_listT l){_start new T[l.size()];_finish _start l.size();_endofstorage _start l.size();iterator it _start;typename initializer_listT::iterator it1 l.begin();while (it1 ! l.end()){*it *it1;}}vectorT operator(initializer_listT l){//调用构造vectorT tmp(l);std::swap(_start, tmp._start);std::swap(_finish, tmp._finish);std::swap(_endofstorage, tmp._endofstorage);return *this;} 3、auto与decltype
3.1 auto 在C98 中 auto 是一个存储类型的说明符表明变量是局部自动存储类型但是局部域中定义局部的变量默认就是自动存储类型所以auto 就没什么价值了。 C11 中废弃 auto 原来的用法将 其用于实现自动类型腿断。这样要求必须进行显示初始化让编译器将定义对象的类型设置为初 始化值的类型。 #includemap
int main()
{auto pf strcpy;cout typeid(pf).name() endl;int i 10;auto p i;cout typeid(p).name() endl;mapstring, string dict { {sort, 排序}, {insert, 插入} };//mapstring, string::iterator it dict.begin();auto it dict.begin(); //自动类型推断return 0;
} 3.2 decltype 关键字 decltype 将变量的类型声明为表达式指定的类型。 decltype是 C11 引入的一个关键字用于推导表达式的类型并生成对应的类型声明。它的语法形式为 decltype(expression) variable_name; 其中 expression 是一个表达式variable_name 是待声明的变量名。decltype 将根据 expression 推导出 variable_name 的类型。 4、范围for循环
C11引入了范围range-basedfor循环它提供了一种简洁的方式来遍历容器比如数组、向量、列表等中的元素其语法如下所示
for (element : container)
{// 执行操作
}其中element 是容器中每个元素的临时变量container 是要遍历的容器。在每次循环迭代中element 都会被赋值为容器中的一个元素直到遍历完整个容器。
范围for循环可以用于大多数标准容器包括向量、列表、集合、映射等。如果你希望在遍历过程中修改容器中的元素则应该使用引用类型的变量作为循环变量如下所示
#include iostream
#include vectorint main()
{std::vectorint numbers {1, 2, 3, 4, 5};// 使用范围for循环修改整型数组中的元素for (int num : numbers){num * 2;}// 输出修改后的数组for (int num : numbers){std::cout num ;}return 0;
}5、右值引用和移动语义
4.1 左值引用和右值引用 在C中引用是一个非常重要的概念它们允许我们在不复制对象的情况下访问对象。C11引入了左值引用lvalue reference和右值引用rvalue reference的概念它们都是引用的一种形式但它们有不同的使用方式和语义。 4.1.1 左值引用
左值引用绑定到左值lvalue即可以取地址的表达式例如变量、对象成员或返回左值的函数调用。左值引用用于引用可以修改的对象常见的情况包括函数参数传递和赋值操作符的重载。左值引用使用 符号声明。 int x 5; int ref x; // ref 是 x 的左值引用 什么是左值什么是左值引用 左值是一个表示数据的表达式 ( 如变量名或解引用的指针 ) 我们可以获取它的地址可以对它赋 值左值可以出现赋值符号的左边右值不能出现在赋值符号左边。 定义时 const 修饰符后的左 值不能给他赋值但是可以取它的地址。左值引用就是给左值的引用给左值取别名。 int main()
{//左值int* ptr new int[10]{ 0 };int a 10;const int c 20;//左值引用int* pp ptr;int d a;//定义时const修饰符后的左值不能给他赋值但是可以取它的地址。//c 3; 不能赋值const int rc c;int pvalue *ptr;return 0;
} 4.1.2 右值引用 右值引用绑定到右值rvalue即临时对象或表达式的结果。右值引用通常用于移动语义和完美转发它们允许我们有效地转移资源的所有权或延长临时对象的生命周期。右值引用使用 符号声明。 int rref 10; // rref 是 10 的右值引用 什么是右值什么是右值引用 右值也是一个表示数据的表达式如字面常量、表达式返回值函数返回值 ( 这个不能是左值引 用返回 ) 等等 右值可以出现在赋值符号的右边但是不能出现出现在赋值符号的左边右值不能 取地址。 右值引用就是对右值的引用给右值取别名。 需要注意的是右值是不能取地址的但是给右值取别名后会导致右值被存储到特定位置且可 以取到该位置的地址. int main()
{int x 1;int y 2;//以下是常见的右值10;x y;//右值引用int r1 x y;int r2 10;//不能取字面量10的地址但是r2引用后可以对r2取地址也可以修改r2。r2 20;//如果不想r2被修改可以用const int r2 去引用//const int r2 10;return 0;
} 左值引用总结 1. 左值引用只能引用左值不能引用右值。 2. 但是 const 左值引用既可引用左值也可引用右值。 右值引用总结 1. 右值引用只能右值不能引用左值。 2. 但是右值引用可以 move 以后的左值。 int y 2; int r3 move(y); 4.2 右值引用使用场景和意义 #define _CRT_SECURE_NO_WARNINGS
#includeiostream
#includeassert.h
using namespace std;
namespace stringtest
{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(string s):_str(nullptr), _size(0), _capacity(0){cout string(string s) -- 移动语义 endl;swap(s);}// 移动赋值string operator(string s){cout string operator(string s) -- 移动语义 endl;swap(s);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};
}void func(stringtest::string s1)
{}
void func2(const stringtest::string s)
{}int main()
{stringtest::string s1(hello world);func(s1);func2(s1);//左值引用减少了拷贝//string operator(char ch)s1 h;return 0;
} 左值引用的短板 但是当函数返回对象是一个局部变量出了函数作用域就不存在了就不能使用左值引用返回只能传值返回。string to_string(int value) 函数中可以看到这里只能使用传值返回传值返回会导致至少1 次拷贝构造 ( 如果是一些旧一点的编译器可能是两次拷贝构造 ) 。 右值引用和移动语义解决上述问题 增加移动构造 移动构造本质是将参数右值的资源窃取过来占位已有那么就不 用做深拷贝了所以它叫做移动构造就是窃取别人的资源来构造自己 。 namespace stringtest
{stringtest::string to_string(int value){bool flag true;if (value 0){flag false;value 0 - value;}stringtest::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;}
}int main()
{stringtest::string s1 stringtest::to_string(1235433);return 0;
} 通过观察 移动构造本质是将参数右值的资源窃取过来占位已有。