STL-list学习笔记

本文详细讲解了C++中链表的结构框架,包括迭代器的作用、封装以及不同类型迭代器的设计。讨论了临时对象在匿名对象、隐式类型转换和函数返回值中的应用,以及拷贝构造和赋值重载的现代复用写法。还提供了list类的源码实现,展示了如何使用模板和迭代器操作链表元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1. 结构框架

2. iterator

3. 临时对象

匿名对象

隐式类型转换

函数返回值

4. 拷贝构造和赋值重载的复用写法

5. list实现源码


1. 结构框架

node是一个结构体,成员有date next prev (public)其他类可以访问

list是链表类,可以以一个指针去访问,增删查改功能函数的实现

iterator是迭代器,方便对于链表结构的访问


2. iterator

为什么使用迭代器,对指针的封装,而不使用原生指针

链表在空间不连续,指针的加减不能很好的访问,通过类定义,内部实现运算符重载

实现iterator类包含一个node*的指针,实现++,--,!= ,*

但是const_iterator怎么实现呢?

typedef const iterator<T> const_iterator;

这样子可行吗?

显然这不行,const_iterator迭代器,目的是date的内容不能被改变,需要可以++和--在链表节点之间访问。

所以迭代器需要三个模板参数,分别对应

数据类型(T)

*返回值(T&或const T&)

->返回值(T*或const T*)

typedef iterator<T, T&, T*> iterator;
typedef iterator<T, const T&, const T*> const_iterator;

当类包含一个指针指向一个对象,那么const 这个类,这个指针指向不能改变,指向的对象反而可以修改


3. 临时对象

临时对象具有常性,出现的场景有匿名对象,隐式类型转换函数的返回值

匿名对象

匿名对象具有常性

T是模板可以是任何类型

T() 匿名对象 只在当前行有效,但是如果是

const T& val = T();

那么匿名对象的生命周期就和val一样,因为val就是匿名对象的名字。

隐式类型转换

double a = 1;

1默认是int类型的在赋值之前,产生了一个临时变量是double类型的1.0,如何再赋值给a;

这个中间产生的临时变量具有常性,不可以被改变,真正具有const性质

自定义类型也可以隐式类型转换,前提是自定义类型具有只有一个参数的构造

函数返回值

当函数的返回值是内置类型int,double等,返回值产生的临时对象其实是const int ,const double

返回值是指针类型,int* 临时对象其实是int* const类型

自定义类型作为返回值虽然具有常性,但是可以改变

iterator end()
{
    return iterator(_head);
}

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

返回的是iterator自定义类型

--end()可行,因为自定义类型的临时对象具有常性,但不是真正的具有常性,可以被修改


4. 拷贝构造和赋值重载的复用写法

构造函数

list()
{
    _head = new node;
}

template<class InputIterator>
list(InputIterator first, InputIterator last)
{
    _head = new node;
    while (first != last)
    {
        push_back(*first);
        ++first;
    }
}

拷贝构造的传统写法

list(const list<T>& x)
{
    _head = new node;
    for (auto e : x)
    {
        push_back(e);
    }
}

拷贝构造的现代复用写法

list(const list<T>& x)
{
    _head = new node;
    list<T> tmp(x.begin(), x.end());
    swap(tmp);
}

 拷贝构造利用前面的迭代器区间构造,构造函数创建tmp局部对象,然后swap交换_head,这样子*this就是和拷贝出来一样,然后对tmp析构

切记要对*this初始化,_head要分配空间,要不然析构tmp的时候就会崩溃

赋值重载的现代复用写法

list<T>& operator=(list<T> x)
{
    _head = new node;
    swap(x);
    return *this;
}

步骤:

1. list<T> x x是拷贝构造出来的局部对象

2. 对*this进行初始化分配空间

3. 交换_head实现内容交换

4. 返回*this 可以引用返回

5. 析构x局部变量


5. list实现源码

list.h

#pragma once
#include <iostream>
#include <list>
#include <assert.h>
using namespace std;

namespace kele
{
	template<class T>
	struct list_node
	{
		typedef list_node<T> node;

		node* _next;
		node* _prev;
		T _date;

		list_node(const T& val = T())
		{
			_date = val;
			_next = this;
			_prev = this;
		}
	};

	template<class T,class Ref,class Ptr>
	struct __list_iterator
	{
		typedef list_node<T> node;
		typedef __list_iterator<T, Ref, Ptr> self;
		node* _it;

		__list_iterator(node* x)
			:_it(x)
		{}

		Ref operator*()
		{
			return _it->_date;
		}

		Ptr operator->()
		{
			return &_it->_date;
		}

		self operator++()
		{
			_it = _it->_next;
			return *this;
		}

		self operator++(int)
		{
			self tmp = *this;
			_it = _it->_next;
			return tmp;
		}

		self operator--()
		{
			_it = _it->_prev;
			return *this;
		}

		self operator--(int)
		{
			self tmp = *this;
			_it = _it->_prev;
			return tmp;
		}

		bool operator!=(const self& x) const
		{
			return _it != x._it;
		}

		bool operator==(const self& x) const
		{
			return _it == x._it;
		}

	};


	template<class T>
	class list
	{
		typedef list_node<T> node;
	public:
		typedef __list_iterator<T, T&, T*> iterator;
		typedef __list_iterator<T, const T&, const T*> const_iterator;

		list()
		{
			_head = new node;
		}

		template<class InputIterator>
		list(InputIterator first, InputIterator last)
		{
			_head = new node;
			while (first != last)
			{
				push_back(*first);
				++first;
			}
		}

		/*list(const list<T>& x)
		{
			_head = new node;
			for (auto e : x)
			{
				push_back(e);
			}
		}*/

		list(const list<T>& x)
		{
			_head = new node;
			list<T> tmp(x.begin(), x.end());
			swap(tmp);
		}

		list<T>& operator=(list<T> x)
		{
			_head = new node;
			swap(x);
			return *this;
		}

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

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

		const_iterator begin() const
		{
			//_head = _head->_next;
			return const_iterator(_head->_next);// const node* const _head 
		}

		iterator end()
		{
			return iterator(_head);
		}

		const_iterator end() const
		{
			return const_iterator(_head);
		}

		void push_back(const T& val)
		{
			//node* tail = _head->_prev;
			//node* newnode = new node(val);

			//tail->_next = newnode;
			//newnode->_prev = tail;
			//newnode->_next = _head;
			//_head->_prev = newnode;
			insert(end(), val);
			//为什么可以--end()
			//因为自定义类型的临时对象具有常性,但不是真正的具有常性,可以被修改
		}

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

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

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

		void insert(iterator pos, const T& val)
		{
			node* prev = pos._it->_prev;
			node* next = pos._it;
			node* newnode = new node(val);

			prev->_next = newnode;
			newnode->_prev = prev;
			newnode->_next = next;
			next->_prev = newnode;
		}

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

			node* prev = pos._it->_prev;
			node* next = pos._it->_next;
			delete pos._it;

			prev->_next = next;
			next->_prev = prev;

			return iterator(next);
		}

		void clear()
		{
			/*while (!empty())
			{
				erase(begin());
			}*/

			iterator it = begin();
			while (it != end())
			{
				/*it = erase(it);*/
				erase(it++);
			}
		}

		void swap(list<T>& x)
		{
			std::swap(this->_head, x._head);
		}

		bool empty()
		{
			return begin() == end();
		}

	private:
		node* _head;
	};

}

test.cpp

#include"list.h"

struct AA
{
	int date1;
	int date2;

	AA(int date1 = 0, int date2 = 0)
		:date1(date1),
		date2(date2)
	{}
};

class Ptr
{
public:
	Ptr(AA& val)
		:p(&val)
	{}

	void print() const//const Ptr* const this
	{
		//this->p->date1
		cout << ++(p->date1) << ":" << p->date2 << endl;
	}
private:
	AA* p;
};


void Print(const kele::list<int>& lt)
{
	kele::list<int>::const_iterator it = lt.begin();
	while (it != lt.end())
	{
		//(*it)++;
		cout << *it << " ";
		++it;
	}
	cout << endl;
}

void test1()
{
	kele::list<int> lt;
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	Print(lt);

	lt.insert(lt.begin(), 10);
	Print(lt);
	lt.erase(lt.begin());
	Print(lt);
	lt.push_front(100);
	lt.push_back(1000);
	
	Print(lt);

	lt.pop_back();
	lt.pop_front();

	Print(lt);

}


//void test2()
//{
//	kele::list<AA> lt;
//	lt.push_back(AA(1, 1));
//	lt.push_back(AA(2, 1));
//	lt.push_back(AA(3, 1));
//	lt.push_back(AA(4, 1));
//	kele::list<AA>::const_iterator it = lt.begin();
//	while (it != lt.end())
//	{
//		cout << it->date1 << ":" << it->date2 << endl;
//		++it;
//	}
//	cout << endl;
//}

void test3()
{
	AA a(1,2);
	Ptr p(a);
	p.print();
}

void test4()
{
	AA a(1, 2);
	const AA* p = &a;
	//(p->date1)++;

}

void test5()
{
	kele::list<int> lt;
	/*kele::list<int> lt2;*/
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);
	Print(lt);
	/*lt2 = lt;*/
	
	kele::list<int> lt2(lt);
	Print(lt2);

}


int main()
{
	test3();
	return 0;
}

完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值