bug记录, 构造与赋值???zzg::list<int> l; l = { 1, 2, 3 };为什么没写对应的赋值函数却可以跑?

1.情景还原

今天我在复习list的时候, 我随手写了下面代码,

cpp 复制代码
zzg::list<int> l; //第二种
l = { 1, 2, 3 };

但是问题是, 我没有实现以initializer_list为参数的赋值运算符重载函数啊???竟然还能能跑, 这是什么情况???

2.问题分析与解答

首先, 我们来看下面两种调用形式:

cpp 复制代码
zzg::list<int> l = { 1, 2, 3 }; //第一种

zzg::list<int> l; //第二种
l = { 1, 2, 3 };

我们分别来说一下调用逻辑, 如果是第一种, 就是直接构造. 调用的函数是:

但是第二种, 就有个问题了. 我现在实现的构造和赋值函数如下: 即无参构造\拷贝构造\initializer_list构造\赋值运算函数重载以及析构函数

我们假定赋值运算符函数用的是传统写法, 即与上图一致, 把现代写法屏蔽掉.

这样写就直接过不了编译阶段. 因为我们没有实现参数匹配的赋值运算符函数重载.

但是我们如果换成现代写法呢? 是可以正常跑的. 因为隐式类型转换之后赋值运算符函数重载的参数匹配了.

这是因为, 代码zzg::list l; 先调用无参构造, 即list(), 之后l = { 1, 2, 3 };调用赋值现代写法, 我们的现代写法参数是list, 此时list会去调用initializer_list构造, 构造出赋值运算符函数现代写法中的参数list, 然后就可以正常跑了.

3.总结

我们总结一下, 就是我随便写了以下代码, 结果能跑令我很疑惑???这什么情况???

疑惑的点在于, 我明明没有写第二行代码能够调用的对应的赋值函数啊?怎么可以跑呢?

这是因为我当时用的是赋值函数重载的现代写法, 恰好利用了list的隐式类型转换, 即第二行代码调用传统写法的赋值函数, 然后又调用了initializer_list为参数的构造来构造了一个list参数对象, 之后就可以跑了.

但是如果用的是现代写法的传统写法, 就会不能跑, 因为参数用的是引用, 不能匹配.

4.参考代码

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

namespace zzg
{
	template<class T>
	struct ListNode
	{
	public:
		T _data;
		struct ListNode<T>* _prev;
		struct ListNode<T>* _next;
	public:
		ListNode(const T& t = T())
			:_data(t)
			,_prev(nullptr)
			,_next(nullptr)
		{}
	};

	template<class T, class Ref, class Ptr>//这里Ref, 即Reference引用的意思, 而Ptr, 指的是pointer, 即指针的意思
	class List_Iterator
	{
		typedef ListNode<T> node;
		typedef List_Iterator<T, Ref, Ptr> Self;
	public:
		node* _ptr;
	public:
		//构造函数
		List_Iterator(node* node)
			:_ptr(node)
		{}

		//++iterator
		Self& operator++()
		{
			_ptr = _ptr->_next;

			return *this;
		}
		//iterator++
		Self operator++(int)
		{
			Self it(_ptr);//构建临时局部对象. 
			_ptr = _ptr->_next;

			return it;
		}
		//--iterator
		Self& operator--()
		{
			_ptr = _ptr->_prev;

			return *this;
		}
		//iterator--
		Self operator--(int)
		{
			Self it(_ptr);
			_ptr = _ptr->_prev;

			return it;
		}
		//*iterator
		//T& operator*()
		//const T& operator*()
		Ref operator*()
		{
			return _ptr->_data;
		}
		//iterator->
		//T* operator->()
		//const T* operator->()
		Ptr operator->()
		{
			return &(_ptr->_data);
		}
		//it1 != it2
		bool operator!=(const List_Iterator<T, Ref, Ptr> l)
		{
			return _ptr != l._ptr;
		}
		//it1 == it2
		bool operator==(const List_Iterator<T, Ref, Ptr> l)
		{
			return _ptr == l._ptr;
		}
	};

	//template<class T>
	//class Const_List_Iterator
	//{
	//	typedef ListNode<T> node;
	//	typedef Const_List_Iterator Self;
	//public:
	//	node* _ptr;
	//public:
	//	//构造函数
	//	Const_List_Iterator(node* node)
	//		:_ptr(node)
	//	{}

	//	//++iterator
	//	Self& operator++()
	//	{
	//		_ptr = _ptr->_next;

	//		return *this;
	//	}
	//	//iterator++
	//	Self operator++(int)
	//	{
	//		Self it(_ptr);//构建临时局部对象. 
	//		_ptr = _ptr->_next;

	//		return it;
	//	}
	//	//--iterator
	//	Self& operator--()
	//	{
	//		_ptr = _ptr->_prev;

	//		return *this;
	//	}
	//	//iterator--
	//	Self operator--(int)
	//	{
	//		Self it(_ptr);
	//		_ptr = _ptr->_prev;

	//		return it;
	//	}
	//	//*iterator
	//	const T& operator*()//这个地方也需要带const
	//	{
	//		return _ptr->_data;
	//	}
	//	//iterator->
	//	const T* operator->()//const T* ptr, 这个的意思是不能*ptr
	//	{
	//		return &(_ptr->_data);
	//	}
	//	//it1 != it2
	//	bool operator!=(const Const_List_Iterator<T> l)
	//	{
	//		return _ptr != l._ptr;
	//	}
	//	//it1 == it2
	//	bool operator==(const Const_List_Iterator<T> l)
	//	{
	//		return _ptr == l._ptr;
	//	}
	//};

	template<class T>
	class list
	{
		typedef ListNode<T> node;
	public:
		typedef List_Iterator<T, T&, T*> iterator;
		typedef List_Iterator<T, const T&, const T*> const_iterator;
	private:
		node* _head;
	public:
		//构造函数
		list()
		{
			cout << "list()" << endl;
			empty_initialization();
		}
		void empty_initialization()
		{
			_head = new node();
			_head->_prev = _head;
			_head->_next = _head;
		}
		//拷贝构造函数
		list(const list<T>& l)
		{
			empty_initialization();
			for (auto& e : l)
			{
				push_back(e);
			}
		}
		//initializer_list构造函数
		list(initializer_list<T> il)
		{
			empty_initialization();//申请一个哨兵位
			cout << "list(initializer_list<T> il)" << endl;
			for (auto& e : il)
			{
				this->push_back(e);
			}
		}

		//赋值运算符函数
		//list<T>& operator=(const list<T>& l)
		//{
		//	clear();//清理原有的资源

		//	for (auto& e : l)
		//	{
		//		push_back(l);
		//	}

		//	return *this;
		//}
		//赋值运算符函数重载, 现代写法
		list<T>& operator=(list<T> l)
		{
			//swap
			node* head = _head;
			_head = l._head;
			l._head = head;

			return *this;
		}
		//析构函数
		~list()
		{
			clear();//释放资源
			delete _head;//释放_head指向的哨兵位资源
			_head = nullptr;//把_head置空
		}

		//迭代器
		iterator begin()
		{
			return iterator(_head->_next);
		}
		iterator end()
		{
			return iterator(_head);
		}
		//const迭代器
		const_iterator begin() const
		{
			return const_iterator(_head->_next);
		}
		const_iterator end() const
		{
			return const_iterator(_head);
		}

		//插入在pos位置之前. 
		void insert(const iterator& pos, const T& data)
		{
			node* newnode = new node(data);
			node* cur = pos._ptr;//指向当前结点
			node* prev = pos._ptr->_prev;
			cur->_prev = newnode;
			newnode->_next = cur;
			newnode->_prev = prev;
			prev->_next = newnode;

			newnode = nullptr;
		}
		void push_back(const T& t)
		{
			insert(end(), t);
		}
		void push_front(const T& t)
		{
			insert(begin(), t);
		}

		//删除
		iterator erase(const iterator& pos)
		{
			node* cur = pos._ptr;
			node* prev = pos._ptr->_prev;
			node* next = pos._ptr->_next;

			prev->_next = next;
			next->_prev = prev;
			free(cur);

			return iterator(next);//构造指向下一个结点的迭代器返回
		}
		iterator pop_back()
		{
			erase(--end());
		}
		iterator pop_front()
		{
			erase(begin());
		}
		void clear()
		{
			iterator it = begin();
			while (it != end())
			{
				it = erase(it);
			}
		}

		size_t size()
		{
			size_t number = 0;

			node* cur = _head;
			while (cur->_next != _head)
			{
				number++;
				cur = cur->_next;
			}

			return number;
		}

		bool empty()
		{
			return size() == 0;
		}
	};

	void test_list1()
	{
		zzg::list<int> l;
		l.push_back(1);
		l.push_back(2);
		l.push_back(3);
		l.push_back(4);
		l.push_back(5);

		zzg::list<int>::iterator it = l.begin();
		while (it != l.end())
		{
			std::cout << ((*it) += 7) << std::endl;

			it++;
		}
	}
	void test_list2()
	{
		zzg::list<int> l;
		cout << "empty : " << l.empty() << endl;

		l.insert(l.end(), 1); // 1
		l.insert(l.end(), 2); // 1 2
		l.insert(l.end(), 3); // 1 2 3
		l.push_front(4); //4 1 2 3
		l.push_back(5); //4 1 2 3 5
		for (auto e : l)
		{
			cout << e << endl;
		}

		cout << "size : " << l.size() << endl;
		cout << "empty : " << l.empty() << endl;
	}

	struct A
	{
		int _a;
		int _b;

		A(int a = 0, int b = 0)
			:_a(a)
			,_b(b)
		{}
	};
	void func_test3(const list<A>& l)
	{
		zzg::list<A>::const_iterator it = l.begin();
		while (it != l.end())
		{
			cout << (it->_a) << " : " << (it->_b) << endl;
			it++;
		}
	}
	void test_list3()
	{
		/*zzg::list<A> l;
		for (int i = 0; i < 6; i++)
		{
			l.push_back({ i, i });
		}
		
		zzg::list<A>::iterator it = l.begin();
		while (it != l.end())
		{
			cout << (*(it))._a << " : " << (*it)._b << endl;
			cout << (it->_a) << " : " << (it->_b) << endl;
			cout << it.operator->()->_a << " : " << it.operator->()->_b << endl;

			it++;
		}*/

		/*const zzg::list<A> l;
		
		zzg::list<A>::const_iterator it = l.begin();
		while (it != l.end())
		{
			cout << it->_a << " : " << it->_b << endl;
			it++;
		}*/
		//这样测试有个大问题, 就是没数据, const list不能插入数据啊..., 想要调用const迭代器还必须得用const list

		//有个好的办法就是让const list去做一个函数参数. 
		zzg::list<A> l;
		for (int i = 0; i < 10; i++)
		{
			l.push_back({i, i});
		}
		func_test3(l);
	}
	void test_list4()
	{
		//zzg::list<int> l = { 1, 2, 3 };
		zzg::list<int> l;
		l = { 1, 2, 3 };

		/*zzg::list<int> cl;
		cl = l;

		for (auto e : l)
		{
			cout << e << endl;
		}

		cout << "---------" << endl;

		for (auto e : cl)
		{
			cout << e << endl;
		}*/
	}
};
#include"list.h"

int main()
{
	//zzg::test_list1();
	//zzg::test_list2();
	//zzg::test_list3();
	zzg::test_list4();

	return 0;
}

EOF

相关推荐
会写代码的孙悟空3 小时前
windows下解决端口被占用,但是找不到占用端口的应用程序;以一种访问权限不允许的方式做了一个访问套接字的尝试;搜索可用端口
运维·网络·windows
sukalot4 小时前
windows 驱动实例分析系列: NDIS 6.0的Filter 驱动改造(二)
windows
喜欢打篮球的普通人5 小时前
2024 Rust现代实用教程:1.3获取rust的库国内源以及windows下的操作
开发语言·windows·rust
sukalot6 小时前
windows 驱动实例分析系列: NDIS 6.0的Filter 驱动改造(四)
windows·单片机·嵌入式硬件
微雨盈萍cbb8 小时前
Windows 上更新OpenSSL 到 1.1.1
windows
askah66448 小时前
无法启动此程序win10玩游戏找不到d3dx9_43.dll缺失的五种常用有效解决方法
windows·游戏·电脑·dll丢失·1024程序员节
约翰先森不喝酒17 小时前
Android BUG 之 Program type already present: MTT.ThirdAppInfoNew
bug
admin_23318 小时前
rsync部署 附报错解决、配置详解及Windows脚本
windows
cpp_learners20 小时前
Windows环境 ffmpeg 命令使用介绍
windows·ffmpeg·ffmpeg命令