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

相关推荐
一禅(OneZen)1 小时前
「Windows/Mac OS」AIGC图片生成视频 ,webui + stable-diffusion环境部署教程
windows·stable diffusion
AirDroid_cn2 小时前
OPPO手机怎样被其他手机远程控制?两台OPPO手机如何相互远程控制?
android·windows·ios·智能手机·iphone·远程工作·远程控制
小龙在山东4 小时前
Python 包管理工具 uv
windows·python·uv
昏睡红猹4 小时前
我在厂里搞wine的日子
windows·wine
love530love7 小时前
Docker 稳定运行与存储优化全攻略(含可视化指南)
运维·人工智能·windows·docker·容器
1024小神12 小时前
tauri项目在windows上的c盘没有权限写入文件
c语言·开发语言·windows
程序视点21 小时前
Window 10文件拷贝总是卡很久?快来试试这款小工具,榨干硬盘速度!
windows
wuk99821 小时前
基于MATLAB编制的锂离子电池伪二维模型
linux·windows·github
zzc92121 小时前
Adobe Illustrator设置的颜色和显示的颜色不对应问题
adobe·bug·illustrator·错误·配色·透明度·底色
lzb_kkk1 天前
【C++】C++四种类型转换操作符详解
开发语言·c++·windows·1024程序员节