当前位置: 首页 > article >正文

C++11编译器优化以及引用折叠

1.左值与右值的意义

1.左值引用和右值引用最终目的是减少拷贝,提高效率

2.左值引用还可以修改参数/返回值

左值引用不足:

部分函数放回场景,只能传值返回,不能引用左值返回

当前函数局部对象,出了当前函数作用域生命周期到了,就销毁了,不能引用左值引用返回,只能传值返回

解决方案一:不用返回值,用输出型参数(牺牲可读性)

解决方案二:编译器优化

解决方案三:右值引用和移动语义

代码示例

把创建的对象变成参数传过去,形参是引用的方式接受,就可以减少拷贝,提高效率。

#include<stdio.h>
#include<vector>
#include<iostream>
using namespace std;

class Solution {
public:
	// 这里的传值返回拷贝代价就太大了
	/*vector<vector<int>> generate(int numRows) {
		vector<vector<int>> vv(numRows);
		for (int i = 0; i < numRows; ++i)
		{
			vv[i].resize(i + 1, 1);
		}
		for (int i = 2; i < numRows; ++i)
		{
			for (int j = 1; j < i; ++j)
			{
				vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
			}
		}
		return vv;
	}*/

	void generate(int numRows, vector<vector<int>>& vv) {
		//vector<vector<int>> vv(numRows);
		vv.resize(numRows);
		for (int i = 0; i < numRows; ++i)
		{
			vv[i].resize(i + 1, 1);
		}
		for (int i = 2; i < numRows; ++i)
		{
			for (int j = 1; j < i; ++j)
			{
				vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];
			}
		}
		for (auto& s : vv)
		{
			for (auto& ss : s)
			{
				cout << ss;
			}
			cout << endl;
		}
		
	}
};

int main()
{
	//vector<vector<int>> ret = Solution().generate(100);
	vector<vector<int>> ret;
	Solution().generate(100, ret);

	
	/*bit::string ret;
	Solution().addStrings("1111111", "222222", ret);*/

	return 0;
}

2.右值对象构造,只有拷贝构造,没有移动构造的场景

下图第一个是在Linux下用指令实现的不优化的场景,先是参数的传过去发生构造,然后把形参进行拷贝构造,俩个参数会有俩次,而后是返回值要拷贝给临时变量有一次拷贝构造,临时变量给ret又会发生拷贝构造。

第二个是1代优化,编译器会有优化,把构造和拷贝构造合成构造,企鹅在返回时不生成临时变量,直接给ret拷贝构造。

第三个是二代优化,连临时变量都不生成,把ret对象的引用传过去,大大提高了效率。

对于赋值的情况

第一个是无优化情况,是先拷贝给临时变量然后在拷贝复制给ret

第二个是一代优化的情况,跟无优化的一样

第三个是二代优化,可以看到只剩拷贝赋值了,把拷贝构造和拷贝赋值合成一个,生成的临时变量是返回对象的引用,就可以减少拷贝构造了

3.有移动构造和移动赋值后

不优化情况,虽然有很多的移动构造存在,但是移动构造的代价很少

一代优化情况下,就是直接返回值对ret进行移动构造,不要临时变量

二代优化情况下,就是str是ret对象的引用,就不会有俩次移动构造

有赋值情况下

不优化情况下是有构造,移动构造和移动赋值

一代优化情况下和不优化是一样的

二代优化是把str变成临时变量的引用,这样就可以省略掉移动构造,这里的临时对象是会有一次构造的

总结

在C++11之前的操作都是非标准的,在C++11后,有了移动构造和移动赋值,前面的优化操作就是锦上添花了,对于深拷贝的传值返回,有了移动构造和移动赋值代价就很小了,而对移动构造和移动赋值进行优化,提升是很小的,可以舍弃的。

 4.引用折叠

C++中不能直接定义引用的引用如int& && r=i;这样写会报错,通过模板或typedef中的类型操作可以构成引用的引用。

通过模板或typedef中的类型操作构成引用时,这时C++11给出了一个引用折叠的规矩:右值引用的右值引用折叠成右值引用,其它组合都是左值引用。

示例代码

// 由于引用折叠限定,f1实例化以后总是一个左值引用
template<class T>
void f1(T& x)
{}

// 由于引用折叠限定,f2实例化后可以是左值引用,也可以是右值引用
template<class T>
void f2(T&& x)
{}

int main()
{
	typedef int& lref;
	typedef int&& rref;
	int n = 0;

	// 引用折叠
	lref& r1 = n; // r1 的类型是 int&
	lref&& r2 = n; // r2 的类型是 int&
	rref& r3 = n; // r3 的类型是 int&
	rref&& r4 = 1; // r4 的类型是 int&&

	// 没有折叠->实例化为void f1(int& x)
	f1<int>(n);
	//f1<int>(0); // 报错

	// 折叠->实例化为void f1(int& x)
	f1<int&>(n);
	//f1<int&>(0); // 报错

	// 折叠->实例化为void f1(int& x)
	f1<int&&>(n);
	//f1<int&&>(0); // 报错

	// 折叠->实例化为void f1(const int& x)
	f1<const int&>(n);
	f1<const int&>(0);

	// 折叠->实例化为void f1(const int& x)
	f1<const int&&>(n);
	f1<const int&&>(0);

	// 没有折叠->实例化为void f2(int&& x)
	//f2<int>(n); // 报错
	f2<int>(0);

	// 折叠->实例化为void f2(int& x)
	f2<int&>(n);
	//f2<int&>(0); // 报错

	// 折叠->实例化为void f2(int&& x)
	//f2<int&&>(n); // 报错
	f2<int&&>(0);

	return 0;
}

万能引用

既可以变成左值引用也可以变成右值引用

 万能引用 
template<class T>
void Function(T&& t)
{
	int a = 0;
	T x = a;
	//x++;

	cout << &a << endl;
	cout << &x << endl << endl;
}

int main()
{
	// 10是右值,推导出T为int,模板实例化为void Function(int&& t)
	//Function(10);

	int a;
	// a是左值,推导出T为int&,引用折叠,模板实例化为void Function(int& t)
	//Function(a); // 左值

	// std::move(a)是右值,推导出T为int,模板实例化为void Function(int&& t)
	//Function(std::move(a));

	const int b = 8;
	// b是左值,推导出T为const int&,引用折叠,模板实例化为void Function(const int& t)
	// 所以Function内部会编译报错,x不能++
	//Function(b);    // const 左值

	// std::move(b)右值,推导出T为const int,模板实例化为void Function(const int&& t)
	// 所以Function内部会编译报错,x不能++
	Function(std::move(b)); // const 右值

	return 0;
}

5.完美转发

function(T&& t)函数模板中,传左值实例化后是左值引用的function函数,传右值实例化以后是右值引用的function函数

前面知识可知,变量表达式都是左值属性,也就意味着一个右值被右值引用绑定后,右值引用变量表达式的属性是左值,在function函数中t的属性是左值,那么把t传递下一层函数,这时匹配的就是左值引用的版本的函数,要保证t对象的属性,就需要使用完美转发来来实现。

代码示例

foword<T>()可以保持对象的属性,如果没有则就不会有一个右值打印出来,因为右值引用会有左值属性

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 < class T>
void Function(T&& t)
{
	Fun(forward<T>(t));
}

int main()
{
	// 10是右值,推导出T为int,模板实例化为void Function(int&& t)
	Function(10); // 右值

	int a;
	// a是左值,推导出T为int&,引用折叠,模板实例化为void Function(int& t)
	Function(a); // 左值

	// std::move(a)是右值,推导出T为int,模板实例化为void Function(int&& t)
	Function(std::move(a)); // 右值

	const int b = 8;
	// a是左值,推导出T为const int&,引用折叠,模板实例化为void Function(const int&t)
	Function(b);

	// std::move(b)右值,推导出T为const int,模板实例化为void Function(const int&&t)
	Function(std::move(b)); // const 右值

	return 0;
}

6.补充

把完美转发引入到自定义list中,模板X会自动推导类型出来。

Lish.h

#pragma once
#include<assert.h>

//#include"Iterator.h"

namespace bit
{
	template<class T>
	struct list_node
	{
		T _data;
		list_node<T>* _next;
		list_node<T>* _prev;

		/*list_node(const T& data = T())
			:_data(data)
			,_next(nullptr)
			,_prev(nullptr)
		{}

		list_node(T&& data)
			:_data(forward<T>(data))
			, _next(nullptr)
			, _prev(nullptr)
		{}*/

		list_node() = default;

		template<class X>
		list_node(X&& data)
			:_data(forward<X>(data))
			, _next(nullptr)
			, _prev(nullptr)
		{}
	};

	template<class T, class Ref, class Ptr>
	struct list_iterator
	{
		typedef list_node<T> Node;
		typedef list_iterator<T, Ref, Ptr> Self;
		Node* _node;

		list_iterator(Node* node)
			:_node(node)
		{}

		Ref operator*()
		{
			return _node->_data;
		}

		Ptr operator->()
		{
			return &_node->_data;
		}

		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		Self operator++(int)
		{
			Self tmp(*this);
			_node = _node->_next;

			return tmp;
		}

		Self& operator--(int)
		{
			Self tmp(*this);
			_node = _node->_prev;

			return tmp;
		}

		bool operator!=(const Self& s) const
		{
			return _node != s._node;
		}

		bool operator==(const Self& s) const
		{
			return _node == s._node;
		}
	};


	/*template<class T>
	struct list_const_iterator
	{
		typedef list_node<T> Node;
		typedef list_const_iterator<T> Self;
		Node* _node;

		list_const_iterator(Node* node)
			:_node(node)
		{}

		const T& operator*()
		{
			return _node->_data;
		}

		const T* operator->()
		{
			return &_node->_data;
		}

		Self& operator++()
		{
			_node = _node->_next;
			return *this;
		}

		Self& operator--()
		{
			_node = _node->_prev;
			return *this;
		}

		Self operator++(int)
		{
			Self tmp(*this);
			_node = _node->_next;

			return tmp;
		}

		Self& operator--(int)
		{
			Self tmp(*this);
			_node = _node->_prev;

			return tmp;
		}

		bool operator!=(const Self& s) const
		{
			return _node != s._node;
		}

		bool operator==(const Self& s) const
		{
			return _node == s._node;
		}
	};*/

	template<class T>
	class list
	{
		typedef list_node<T> Node;
	public:
		/*typedef list_iterator<T> iterator;
		typedef list_const_iterator<T> const_iterator;*/

		typedef list_iterator<T, T&, T*> iterator;
		typedef list_iterator<T, const T&, const T*> const_iterator;
		//typedef ReverseIterator<iterator, T&, T*> reverse_iterator;
		//typedef ReverseIterator<const_iterator, const T&, const T*> const_reverse_iterator;

		//reverse_iterator rbegin()
		//{
		//	return reverse_iterator(--end());
		//}

		//reverse_iterator rend()
		//{
		//	return reverse_iterator(end());
		//}

		// 对称
	/*	reverse_iterator rbegin()
		{
			return reverse_iterator(end());
		}

		reverse_iterator rend()
		{
			return reverse_iterator(begin());
		}

		const_reverse_iterator rbegin() const
		{
			return const_reverse_iterator(end());
		}

		const_reverse_iterator rend() const
		{
			return const_reverse_iterator(begin());
		}*/

		iterator begin()
		{
			return _head->_next;
		}

		iterator end()
		{
			return _head;
		}

		const_iterator begin() const
		{
			return _head->_next;
		}

		const_iterator end() const
		{
			return _head;
		}

		void empty_init()
		{
			_head = new Node;
			_head->_next = _head;
			_head->_prev = _head;
			_size = 0;
		}

		list()
		{
			empty_init();
		}

		list(initializer_list<T> il)
		{
			empty_init();
			for (auto& e : il)
			{
				push_back(e);
			}
		}

		// lt2(lt1)
		list(const list<T>& lt)
		{
			empty_init();

			for (auto& e : lt)
			{
				push_back(e);
			}
		}

		// lt1 = lt3
		list<T>& operator=(list<T> lt)
		{
			swap(lt);
			return *this;
		}

		~list()
		{
			clear();
			delete _head;
			_head = nullptr;
		}

		void clear()
		{
			auto it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

		// 16:18继续
		void swap(list<T>& lt)
		{
			std::swap(_head, lt._head);
			std::swap(_size, lt._size);
		}

		/*void push_back(const T& x)
		{
			insert(end(), x);
		}

		void push_back(T&& x)
		{
			insert(end(), forward<T>(x));
		}*/

		// 万能引用
		template<class X>
		void push_back(X&& x)
		{
			insert(end(), forward<X>(x));
		}

		void push_front(const T& x)
		{
			insert(begin(), x);
		}

		//iterator insert(iterator pos, const T& x)
		//{
		//	Node* cur = pos._node;
		//	Node* prev = cur->_prev;
		//	Node* newnode = new Node(x);

		//	// prev newnode cur
		//	newnode->_next = cur;
		//	cur->_prev = newnode;
		//	newnode->_prev = prev;
		//	prev->_next = newnode;

		//	++_size;

		//	return newnode;
		//}

		//iterator insert(iterator pos, T&& x)
		//{
		//	Node* cur = pos._node;
		//	Node* prev = cur->_prev;
		//	Node* newnode = new Node(forward<T>(x));

		//	// prev newnode cur
		//	newnode->_next = cur;
		//	cur->_prev = newnode;
		//	newnode->_prev = prev;
		//	prev->_next = newnode;

		//	++_size;

		//	return newnode;
		//}

		template<class X>
		iterator insert(iterator pos, X&& x)
		{
			Node* cur = pos._node;
			Node* prev = cur->_prev;
			Node* newnode = new Node(forward<X>(x));

			// prev newnode cur
			newnode->_next = cur;
			cur->_prev = newnode;
			newnode->_prev = prev;
			prev->_next = newnode;

			++_size;

			return newnode;
		}

		void pop_back()
		{
			erase(--end());
		}

		void pop_front()
		{
			erase(begin());
		}

		iterator erase(iterator pos)
		{
			assert(pos != end());

			Node* prev = pos._node->_prev;
			Node* next = pos._node->_next;

			prev->_next = next;
			next->_prev = prev;
			delete pos._node;

			--_size;

			return next;
		}

		size_t size() const
		{
			return _size;
		}

		bool empty() const
		{
			return _size == 0;
		}
	private:
		Node* _head;
		size_t _size;
	};

	struct AA
	{
		int _a1 = 1;
		int _a2 = 1;
	};

	 按需实例化
	 T* const ptr1
	 const T* ptr2
	//template<class Container>
	//void print_container(const Container& con)
	//{
	//	// const iterator -> 迭代器本身不能修改
	//	// const_iterator -> 指向内容不能修改
	//	typename Container::const_iterator it = con.begin();
	//	//auto it = con.begin();
	//	while (it != con.end())
	//	{
	//		//*it += 10;

	//		cout << *it << " ";
	//		++it;
	//	}
	//	cout << endl;

	//	for (auto e : con)
	//	{
	//		cout << e << " ";
	//	}
	//	cout << endl;
	//}

	
}

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1

#include<vector>
#include<iostream>
#include<map>
#include<string>
#include<assert.h>
using namespace std;
#include<list>
#include"Lish.h"

namespace bit
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		iterator begin()
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			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);
		}

		// 拷贝构造
		string(const string& s)
			:_str(nullptr)
		{
			cout << "string(const string& s) -- 拷贝构造" << endl;
			reserve(s._capacity);
			for (auto ch : s)
			{
				push_back(ch);
			}
		}

		void swap(string& ss)
		{
			::swap(_str, ss._str);
			::swap(_size, ss._size);
			::swap(_capacity, ss._capacity);
		}

		// 移动构造
		string(string&& s)
		{
			cout << "string(string&& s) -- 移动构造" << endl;
			// 转移掠夺你的资源
			swap(s);
		}

		string& operator=(const string& s)
		{
			cout << "string& operator=(const string& s) -- 拷贝赋值" <<
				endl;
			if (this != &s)
			{
				_str[0] = '\0';
				_size = 0;
				reserve(s._capacity);
				for (auto ch : s)
				{
					push_back(ch);
				}
			}
			return *this;
		}

		// 移动赋值
		string& operator=(string&& s)
		{
			cout << "string& operator=(string&& s) -- 移动赋值" << endl;
			swap(s);
			return *this;
		}

		~string()
		{
			//cout << "~string() -- 析构" << endl;
			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];
				if (_str)
				{
					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)
		{
			push_back(ch);
			return *this;
		}

		const char* c_str() const
		{
			return _str;
		}

		size_t size() const
		{
			return _size;
		}
	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0;
	};
}

class Solution {
public:
	// 传值返回需要拷贝
	bit::string addStrings(bit::string num1, bit::string num2) {
		bit::string str;
		int end1 = num1.size() - 1, end2 = num2.size() - 1;
		// 进位
		int next = 0;
		while (end1 >= 0 || end2 >= 0)
		{
			int val1 = end1 >= 0 ? num1[end1--] - '0' : 0;
			int val2 = end2 >= 0 ? num2[end2--] - '0' : 0;
			int ret = val1 + val2 + next;
			next = ret / 10;
			ret = ret % 10;
			str += ('0' + ret);
		}
		if (next == 1)
			str += '1';
		reverse(str.begin(), str.end());
		//cout << &str << endl;

		return str;
	}
};

int main()
{
	bit::list<bit::string> lt;
	bit::string s1("11111111111");
	lt.push_back(s1);

	bit::string s2("33333333333");
	lt.push_back(move(s2));

	lt.push_back("22222222222");

}


http://www.kler.cn/a/467743.html

相关文章:

  • Python爬虫基础——认识网页结构(各种标签的使用)
  • 【Java数据结构】二叉树
  • 【数学建模笔记】评价模型-基于熵权法的TOPSIS模型
  • 东京大学联合Adobe提出基于指令的图像编辑模型InstructMove,可通过观察视频中的动作来实现基于指令的图像编辑。
  • 【LeetCode Hot100 二分查找】搜索插入位置、搜索二维矩阵、搜索旋转排序数组、寻找两个正序数组的中位数
  • 在Linux中,如何查看和修改网络接口配置?
  • 加密算法分类与介绍:保障信息安全的核心技术
  • 【Leetcode】731. 我的日程安排表 II
  • 大麦抢票科技狠活
  • 【WPF】 数据绑定机制之INotifyPropertyChanged
  • 【华为OD-E卷 - 网上商城优惠活动 100分(python、java、c++、js、c)】
  • Huawei LiteOS 开发指南
  • AWS 申请证书、配置load balancer、配置域名
  • springboot3 redis 批量删除特定的 key 或带有特定前缀的 key
  • 我用AI学Android Jetpack Compose之入门篇(2)
  • 044_小驰私房菜_MTK平台Camera关闭多帧
  • 金融租赁系统的创新与发展推动行业效率提升
  • 使用python调用翻译大模型实现本地翻译【exe客户端版】
  • c#2025/1/4 周六
  • HTML5 手风琴(Accordion)详解
  • 基于单片机的俄罗斯方块设计
  • badboy坏男孩批量抓取录制接口(接口可导入到jmeter中使用)
  • node.js之---事件循环机制
  • 力扣【SQL连续问题】
  • Spring源码分析之事件机制——观察者模式(二)
  • 理解linux内核中的几种地址