栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

中级C++11:大括号初始化、decltype、typeid、右值引用、移动语义、完美转发

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

中级C++11:大括号初始化、decltype、typeid、右值引用、移动语义、完美转发

文章目录
  • C++11特性
  • 大括号的花样使用
  • 变量类型的推导decltype、typeid
  • 增加的新容器
  • 右值引用
  • 移动语义
    • 右值引用、移动语义总结:
  • 完美转发
  • 新增的成员函数
  • G.

C++11特性
  • 相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中约600个缺陷的修正,这使得C++11更像是从C++98/03中孕育出的一种新语言。
  • 相比较而言,C++11能更好地用于系统开发和库开发、语法更加泛华和简单化、更加稳定和安全,不仅功能更强大,而且能提升程序员的开发效率。
  • 用一下常见的特性即可
大括号的花样使用
  • C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。
  • 调用的自定义类型的构造函数。
int main()
{
	int a[]{ 21, 22, 23, 24 };
	map v1{ {"endeavour",24} };//主要支持了initializer_list 作为参数的构造函数

	//vector v2(1, 2, 3); 必须要有对应参数类型和个数的构造函数

	initializer_list lt1{ 21,22,23 };
	auto it = lt1.begin();
	while (it != lt1.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;

	vector* v2 = new vector[4]{ {24,25,26} };
	int* p1 = new int[3] { 24, 25, 26 };
	int* p2 = new int(27);
	return 0;
}
变量类型的推导decltype、typeid
  • 推演表达式类型作为变量的定义类型
  • 推演函数返回值的类型
int main()
{
	int a[]{ 21, 22, 23, 24 };
	map v1{ {"endeavour",24} };
	initializer_list lt1{ 21,22,23 };
	
	auto pa = &a;
	auto pm = &v1;
	auto plt = <1;

	vector vv;//返回的是一个类型

	cout << typeid(pa).name() << endl< 
增加的新容器 

int main()
{
	int a[]{ 21, 22, 23, 24 };
	array  ai{ 25,26,27 };
	a[11] = 28;//对越界是一种抽查
	ai[6] = 29;//检查更严格。

	//另外有用的就是 哈希表的 map set
	return 0;
}
右值引用
  • 普通左值引用只能引用左值,不能引用右值,const引用既可引用左值,也可引用右值。
  • 右值引用:只能引用右值,一般情况不能直接引用左值。
    • std::move()函数位于 头文件中,该函数名字具有迷惑性,它并不搬移任何东西,唯一的功能就是将一个左值强制转化为右值引用,然后实现移动语义。
    • 被转化的左值,其生命周期并没有随着左值的转化而改变,即std::move转化的左值变量lvalue不会被销毁。
    • STL中也有另一个move函数,就是将一个范围中的元素搬移到另一个位置。

int main()
{
	int a = 24;//左值可以取地址,可以赋值;const左值可以取地址,不能赋值,在内存中有地址。
	int& b = a;
	int c = b;
	const int& d = 24;  //const左值可以引用右值

	
	//25 = a;            //右值具有常性,不能取地址,不能出现再取值符号的左边,不能修改,因为在内存中没有地址
	//25 = 1;
	//int* pc = &25;

	int&& f = 25;  //右值引用后的c  是左值。
	f = 27;

	//int&& e = a;  //右值引用不能引用 左值
	int&& e = move(a);  //右值引用可以引用 move以后的左值

	return 0;
}


左值引用的盲区:

mystring::String f2()
{
	mystring::String s("hhee");
	return s;
}
int main()
{
	mystring::String s1 = f2();
	return 0;
}
  • s返回前 会产生一个临时对象,深拷贝拷贝s;tmp(s);然后s出作用域自动析构;
  • 然后s1(tmp),在进行一次深拷贝构造 ,这个过程连续,被编译器优化了
  • 这里的 = 号 不是赋值重载,这里是刚创建的对象用一个对象初始化。
  • 如果s的数据量很大,那么开销很大,两次申请,两次strcpy,两次析构…
  • 如果加static,引用返回,会有多线程安全问题:多线程使用的都是这一份。
移动语义
  • 将一个对象中资源移动到另一个对象中的方式,可以有效缓解该问题。
  • 有了移动语义后,函数外若有对象接受返回的参数时,会把返回值处理成 将亡值(右值)。直接进行一次移动构造即可,不用在进行原来的两次拷贝构造。

namespace mystring
{
    class stirng
   {
   ....
	private:
		char* _str;
		size_t _size;
		size_t _capacity; // 不包含最后做标识的
   };
}

swap:

      // s1.swap(s2)
		void swap(string& s)
		{
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}

移动构造:

        string(string&& s)
			:_str(nullptr)
			, _size(0)
			,_capacity(0)
		{
			cout << "string(string&& s) -- 移动拷贝" << endl;
			//this->swap(s);
			swap(s);
		}

移动赋值:

       string& operator=(string&& s)
		{
			cout << "string& operator=(string&& s) -- 移动赋值" << endl;
			swap(s);

			return *this;
		}

右值引用、移动语义总结:
  • 所有的STL容器都增加了移动构造,移动赋值重载;面对常量时,效率更高。

  • C++11中,算法里面的swap和容器里面的swap效率没有区别。

    右值引用:

  1. 实现移动语义(移动构造与移动赋值)
  2. 给中间临时变量取别名:
  3. 实现完美转发…
int main()
{
 string s1("hello");
 string s2(" world");
 string s3 = s1 + s2; // s3是用s1和s2拼接完成之后的结果拷贝构造的新对象
 stirng&& s4 = s1 + s2; // s4就是s1和s2拼接完成之后结果的别名  表达式结果具有常性时右值
 return 0;
}
完美转发
  • 完美转发是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另外一个函数。
  • 如果相应实参是左值,它就应该被转发为左值;如果相应实参是右值,它就应该被转发为右值。
  • 模板里面的T&& 做参数,不再局限是右值引用,叫做万能引用;即可引用左值,也可以引用右值;但接受一个参数后民退化成左值,用std::forward可以保持右值属性。
void Fun(int &x){ cout << "左值引用" << endl; }
void Fun(const int &x){ cout << "const 左值引用" << endl; }

void Fun(int &&x){ cout << "右值引用" << endl; }
void Fun(const int &&x){ cout << "const 右值引用" << endl; }

template
void PerfectForward(T&& x)
{
	//Fun(x);
	Fun(std::forward(x));
}

新增的成员函数
  • 移动构造/移动赋值 。

  • 如果 没有定义 拷贝构造/拷贝赋值/移动构造/移动赋值/析构函数的 任何一个,编译器会 自动生成 移动构造/移动赋值 函数

  • 如果 需要定义 拷贝构造/拷贝赋值/移动构造/移动赋值/析构 函数的任何一个,不要忘了 移动构造/移动赋值 函数,否则右值会走普通的拷贝构造。

  • 条件很苛刻,对于需要深拷贝的类,都需要自己写。

G.
  • 大脑一片混乱…
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1001212.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号