string STL容器 尾插插入的操作。

这篇博客探讨了C++中STL string对象的构造、拷贝构造函数和赋值运算符的实现,包括深拷贝与浅拷贝的区别,以及现代C++的拷贝构造和赋值运算符的实现方式。文章通过实例展示了如何避免内存泄漏和确保对象正确管理内存。

// 面向对象 STLstring 使用.cpp : 此文件包含 “main” 函数。程序执行将在此处开始并结束。
//
//#include
//
//int main()
//{
// std::cout << “Hello World!\n”;
//}
//
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧:
// 1. 使用解决方案资源管理器窗口添加/管理文件
// 2. 使用团队资源管理器窗口连接到源代码管理
// 3. 使用输出窗口查看生成输出和其他消息
// 4. 使用错误列表窗口查看错误
// 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目
// 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件

////string 使用
//#include
//#include
//using namespace std;
//class String
//{
//public:
// //String()
// // :_data(new char[1])
// //{
// // _data[0] = ‘\0’;
// //}
// //全缺省构造函数 一般使用的就是全缺省的情况
// String(const char* str = “”)
// :_data(new char[strlen(str) + 1])
// {
// strcpy(_data, str);
// cout << “String(char*)” << endl;
// }
// const char* c_str() const
// {
//
// return _data;
// }
// ~String()
// {
// if (_data)
// {
// //析构函数的时候就是使用的是[]也是用删除连续空间大小的
// //注意资源申请是在堆上进行的,资源的释放也是在堆上的。
// delete[] _data;
// _data = nullptr;
// cout << “String()” << endl;
// }
//
// }
//private:
// char* _data;
//
//};
//void test()
//{
// String str;
// cout << str.c_str() << endl;
// String str2;
// cout << str2.c_str() << endl;
//}
//int main()
//{
// test();
// return 0;
//}

//
//#include
//#include
//using namespace std
////经典写法
//class String
//{
//public:
// //String()
// // :_data(new char[1])
// //{
// // _data[0] = ‘\0’;
// //}
// //全缺省构造函数 一般使用的就是全缺省的情况
// String(const char* str = “”)
// :_data(new char[strlen(str) + 1])
// {
// strcpy(_data, str);
// cout << “String(char*)” << endl;
// }
// //由于会出现浅拷贝的问题,那么就是显示去重载 进行深拷贝
// //之所以是深拷贝,就是因为有新开辟的空间,再去拷贝
// String(const String& str)
// //这里是开辟空间。
// //
// :_data(new char[strlen(str._data)+1])
// {
// strcpy(_data, str._data);
// }
////对应的是浅拷贝
//String(const String& str)
// :_data(str._data)
//{
// //函数体内是空的,只是地址的拷贝。
//}
// const char* c_str() const
// {
//
// return _data;
// }
// String& operator=(const String& str)
// {
// //深拷贝
// //判断是不是自己给自己赋值 如果是自己就直接返回。
// if (this != &str)
// {
// //1.释放原有的空间
// delete[] _data;
// //2.申请新的空间
// _data = new char[strlen(str._data) + 1];
// //3.拷贝内容
// strcpy(_data, str._data);
// }
// return this;
// }
// ~String()
// {
// if (_data)
// {
// //析构函数的时候就是使用的是[]也是用删除连续空间大小的
// //注意资源申请是在堆上进行的,资源的释放也是在堆上的。
// delete[] _data;
// _data = nullptr;
// cout << “String()” << endl;
// }
//
// }
//private:
// char
_data;
//};
//void test()
//{
// String str(“123”);
// //浅拷贝;只拷贝string对象中的内容 拷贝构造
// //String copy(str);
// //赋值
// String str2 = str;//浅拷贝 内存泄漏
// String str3;
// str2 = str;
// str3 = str2;
//
// //拷贝构造; 判断是否是拷贝构造,就是需要去判断该对象是否是存在的,不存在就是拷贝构造,存在就是赋值。
// String str4 = str;
//
//}
//int main()
//{
// test();
// return 0;
//}

//
//#include
//#include
//using namespace std;
//class String
//{
//public:
//
// //全缺省构造函数 一般使用的就是全缺省的情况 这里使用的是const就是不发生改变。
// String(const char* str = “”)
// //根据长度进行空间的申请,并且是初始化。空间的申请使用new进行空间的申请。
// :_data(new char[strlen(str) + 1])
// {
// //调用默认的拷贝构造。
// strcpy(_data, str);
// cout << “String(char*)” << endl;
// }
// //现代写法; 主要是代码的复用。复用构造函数的逻辑,完成实际的拷贝。
// //拷贝构造
// String(const String& str)
// {
// string tmp(str._data);
// //这里的交换就是交换指针的指向,从而实现空间的释放,完成拷贝的任务。
// swap(tmp._data, _data);
// }
// //现代写法的赋值的写法;
// //释放原有空间,申请新的空间,拷贝内容
// //赋值运算符;
// //1.通过一个形参对象,调用拷贝构造,完成;
// //a.新的空间申请
// //b.内容拷贝
// //2.调用形参对象的析构,完成
// //c.原有空间释放。
// String& operator=(const String& str)
// {
// string tmp(str._data);
// swap(tmp._data, _data);
// }
// ~String()
// {
// if (_data)
// {
// //析构函数的时候就是使用的是[]也是用删除连续空间大小的
// //注意资源申请是在堆上进行的,资源的释放也是在堆上的。
// delete[] _data;
// _data = nullptr;
// cout << “String()” << endl;
// }
// }
//private:
// char* _data;
//}:
//void test()
//{
// String str(“123”);
// String copy(str);
// String str2(“456”);
// str2 = str;
//
//}
//int main()
//{
// tets();
// return 0;
//}

#include<assert.h>
#include
#include
using namespace std;
//进行增删查改的操作 就是类似于一个顺序表的操作。
class String
{
public:
//string的迭代器 类似于字符指针。
//迭代器操作;类似于指针
//解引用:iterator–>获取内容
//移动++iterator,–iterator,移动到相邻的位置。
typedef char
iterator;
typedef const char* const_iterator;
const_iterator begin() const
{
return _data;
}
const_iterator end()const
{
//最后元素的下一个位置。
return _data + _size;
}
String(const char* str = “”)
{
//提高性能
_size = strlen(str);
_data = new char[_size + 1];
_capacity = _size;

	strcpy(_data, str);
}
String(const string& str)
	:_data(nullptr)
	, _size(0)
	, _capacity(0)
{
	String tmp(str._data);
	swap(tmp);

}
//交换的函数
void swap(String& str)
{
	swap(_data,str._data);
	swap(_size,str._size);
	swap(_capacity,str._capacity);
}
String& operator=(String str)
{
	swap(str);
}
~String()
{
	if (_data)
	{
		delete[] _data;
		_data = nullptr;
		_size = _capacity = 0;
	}
}
//输出对应位置的内容
char& operator[](size_t pos)
{
	assert(pos < _size);
	return _data[pos];
}
//只读
const char& operator[](size_t pos) const
{
	assert(pos < _size);
	return _data[pos];
}
//返回当前有效字符的个数
size_t size() const
{
	return _size;
}
//尾插
void push_back(const char& ch)
{
	//检查空间
	if (_size == _capacity)
	{
		size_t newC = _capacity == 0?15:2 * _capacity;
		//增容  细节就是是不是为0
		reserve(newC);
	}
	_data[_size] = ch;
	_size++;
	//添加结束字符‘\0’ 保证是一个完整的字符串。
	_data[_size] = '\0';
}
void reserve(size_t n)
{
	if (n> _capacity)
	{
		//申请空间
		char* tmp = new char[n + 1];
		//拷贝
		strcpy(tmp, _data);
		//释放原有空间
		delete[] _data;
		//更新指向和容量。
		_data = tmp;
		_capacity = n;
	}

}
void resize(size_t n, const char& ch = '\0')
{
	//3.n>_capacity 增容
	if (n > _capacity)
	{
		reserve(n);
	}
	//2._size<n<=_capacity
	//填充字符 ch
	if(n>_size)
	memset(_data + _size, ch, (n - _size) * sizeof(char));
	//1.直接修改size
	_size = n;
	_data[_size] = '\0';
}
const char* c_str() const
{
	return _data;
}

private:
char* _data;
//size;有效字符的个数
size_t _size;
//capacity;可以保存的最大有效字符个数
size_t _capacity;
};
//void test()
//{
// String str = “0123456789”;
// for (size_t i = 0; i < str.size(); ++i)
// {
// cout << str[i] << “”;
// //str.operator;
// str[i] = ‘a’;
// str.operator = ‘b’;
// }
// cout << endl;
//
// //范围for 通过迭代器实现 底层是迭代器的接口。
// for (const auto& ch : str)
// {
// cout << ch << “”;
// }
// cout << endl;
// //迭代器的使用方式
// String:: iterator it = str.begin();
// while (it != str.end())
// {
// cout << *it << “”;
// *it = ‘d’;//遍历完成之后就都是b了
// ++it;
// }
//}
//int main()
//{
// test();
// return 0;
//
//}
//
////const迭代器
//void printStringIt(const string& str)
//{
// string::const_iterator it = str.begin();
// while (it != str.end())
// {
// cout << *it << " ";
// //由于是const 所以不能进行修改
// ++it;
// }
// cout << endl;
//}
//
//void printStringFor(const string& str)
//{
// for (const char& ch : str)
// {
// cout << ch << “”;
// //ch=‘a’;
// }
// cout << endl;
//}

//尾插的操作
void test()
{
String str;
str.push_back(‘1’);
cout << str.c_str() << endl;
str.push_back(‘2’);
cout << str.c_str() << endl;
str.push_back(‘3’);
cout << str.c_str() << endl;
str.push_back(‘4’);
cout << str.c_str() << endl;
str.push_back(‘5’);
cout << str.c_str() << endl;
str.push_back(‘6’);
cout << str.c_str() << endl;
str.resize(3);//123
str.resize(10, a);//123aaaaaaa
str.resize(20, b);//123aaaaaaabbbbbbbbbb
}

int main()
{
test();
return 0;

}

1.自定义容器:FlexibleList 功能概述:实现一个类似于std:list的双向链表容器FlexibleList,但它能够支持动态类型存储(可以存 储不同类型的数据),即在一个链表中存储如int、double、std::string等不同类型的数据 构造函数:提供默认构造函数、拷贝构造函数和带初始元素的构造函数。 插入操作:实现push_front、push_back、insert等方法,将元素插入到链表的不同位置。 删除操作:实现pop_front、pop_back、erase等方法,从链表中移除元素。 访问操作:提供front、back方法获取链表的首元素,以及支持迭代器遍历链表。 内存管理:确保在插入和删除元素时,能够正确管理内存,避免内存泄漏。 2.自定义算法:AdvancedSort 功能概述:实现一个高级排序算法AdvancedSort,它可以对FlexibleList中的元素进行排序,默认设计 2个参数,一个参数表示对FlexibleList中特定的类型进行排序,第二个参数表示排序规则,该规则需要 支持多种排序规则,如升序、降序,并且可以根据元素的自定义属性进行排序。 模板实现:使用模板编程,使算法可以处理不同类型的元素。 自定义比较函数:允许用户传入自定义的比较函数,以实现灵活的排序规则。 效率优化:尽量采用高效的排序算法,如快速排序或归并排序,确保排序时间复杂度尽可能的小。 3.自定义迭代器:Flexiblelterator 功能概述:为FlexibleList实现自定义迭代器Flexiblelterator,使其能够像STL容器的迭代器一样工 作,支持++、--、*等操作。 具体要求:双向迭代:支持正向和反向迭代,即可以使用++和操作符移动迭代器。 解引用操作:通过*操作符可以访问迭代器指向的元素。 范围for循环支持:使FlexibleList能够使用范围for循环进行遍历。 示例用法 struct Person { std::string name; int age; }; Person p1C"jack",20); Person p2("rose",30); FlexibleList dbList = {100,200,30,3.14,9.87,27,39,15,"test","hello",p1,p2,p3}; bool ascending(int a,int b){ return a > b; } AdvancedSort(dbList.begin(),dbList.end(),typeid(int));//默认升序排序 AdvancedSort(dbList.begin(),dbList.end(),typeid(int),ascending); print_AdvancedSort(dbList,typeid(int));//只输出对应的数据即可。 bool ascending (Person &t1,Person &t2) { return t1.age > t2.age; } AdvancedSort (dbList.begin(),dbList.end(),typeid(Person),ascending); print_Advancedsort(dbList,typeid(Person));//按照排序输出一行数据就行,按照上述需求和使用示例来完成整个代码,确保代码可以正确运行
最新发布
03-27
<think>嗯,用户想基于C++ STL实现一个支持动态类型存储的双向链表容器FlexibleList,同时还要实现高级排序算法AdvancedSort和自定义迭代器FlexibleIterator。这看起来有点复杂,我得仔细拆解问题。 首先,FlexibleList需要支持动态类型存储,也就是说容器里的元素可以是不同类型的。这让我想到C++17的std::any,它可以存储任意类型的值。所以FlexibleList的节点应该用std::any来保存数据。不过,使用std::any需要注意类型安全,访问时需要知道具体类型才能提取值。另外,双向链表的结构需要每个节点有指向前后的指针,这点和std::list类似,但需要自己实现节点结构。 接下来是插入、删除和访问操作插入的话,可能需要实现push_front、push_back这样的方法,同时在指定位置插入。删除操作如pop_front、pop_back,以及根据迭代器位置删除。访问操作可能需要通过迭代器进行,或者提供类似front()、back()的方法。内存管理方面,需要注意在插入时分配节点内存,删除时释放,避免内存泄漏。可能需要使用智能指针来管理节点,但双向链表通常用原始指针,因为每个节点需要被前后节点引用,所以可能需要自己处理析构函数来释放所有节点。 然后是AdvancedSort算法。这个算法需要针对FlexibleList中的特定类型进行排序,并且支持自定义比较规则。因为FlexibleList存储的是std::any,所以在排序时需要确定元素的类型。用户可能需要提供一个谓词(predicate),用来比较元素。但如何确保元素类型一致呢?或者,用户需要在比较时进行类型检查,如果类型不符合则抛出异常或者跳过?或者,AdvancedSort只能对同一类型的元素进行排序,其他类型的元素会被排除?这需要进一步明确需求。另外,排序算法本身可以选择归并排序,因为链表结构适合归并排序,时间复杂度是O(n log n),而且不需要随机访问。 自定义迭代器FlexibleIterator需要符合STL风格,支持范围for循环。STL迭代器需要满足一定的类别,比如双向迭代器,需要实现operator++、operator--、解引用等操作。由于FlexibleList的元素是std::any,解引用操作符应该返回std::any&,让用户自己处理类型转换。迭代器还需要支持begin()和end()方法,这样范围for才能使用。此外,需要注意const迭代器和非const迭代器的区别,可能需要实现const版本的迭代器。 现在,整合这些部分。FlexibleList类需要包含节点结构,每个节点包含std::any数据,前后指针。然后定义迭代器类,里面包含指向节点的指针,并重载必要的操作符。AdvancedSort作为友元函数或者独立的模板函数,接受FlexibleList和比较函数作为参数,进行排序。排序时需要遍历链表,比较元素,但需要处理std::any的类型问题,可能需要用户提供类型转换的方法或者比较函数内部处理类型判断。 可能的挑战:如何处理不同类型的元素排序?比如,如果链表中有int和string,如何比较?可能需要用户指定排序的类型,只对该类型元素进行排序,或者比较函数能够处理多类型,但这会增加复杂度。可能用户需求是FlexibleList存储同一类型,但使用std::any来实现动态类型,但实际使用时可能限制为同一类型。或者,用户希望存储不同类型,但排序时只处理特定类型,其余元素放在末或开头?这需要进一步明确,但根据问题描述,可能用户希望FlexibleList能够存储不同类型,但排序时根据特定类型进行比较,比如只对int类型元素排序,其他类型保持不变?或者用户希望所有元素都是同一类型,但FlexibleList允许在运行时存储不同类型,但排序时需要元素类型一致? 可能解决方案:在AdvancedSort中,用户需要提供一个比较函数,该函数接受两个std::any参数,并能够进行比较。例如,用户可能只想比较int类型的元素,如果元素不是int类型,则抛出异常或在比较函数中处理。或者,比较函数内部检查类型,如果类型不符,则按某种规则处理(如视为更大或更小)。这可能需要在比较函数中进行类型判断,例如: bool compareAny(const std::any& a, const std::any& b) { if (a.type() != typeid(int) || b.type() != typeid(int)) { return false; // 或者抛出异常 } return std::any_cast<int>(a) < std::any_cast<int>(b); } 但这样的比较函数可能不适合作为排序的谓词,因为需要严格的弱序。因此,可能AdvancedSort只能对同一类型的元素进行排序,否则行为未定义。或者,用户必须确保所有元素类型相同,或者在比较函数中处理类型问题。 另外,内存管理方面,FlexibleList需要正确管理节点的创建和销毁。在析构函数中,需要遍历所有节点并释放内存。使用原始指针的话,需要确保在删除节点时正确连接前后节点的指针,避免悬空指针。 迭代器的实现需要注意操作符的重载,比如operator->需要返回指向std::any的指针,但用户可能需要通过any_cast来获取实际类型。例如: auto it = list.begin(); int value = std::any_cast<int>(*it); 如果实际类型不匹配,会抛出异常。因此,用户需要自己确保类型正确。 示例用法部分,可能需要展示如何存储不同类型,比如插入int、string等,然后排序时只处理int类型元素。但如何实现这一点可能需要AdvancedSort接受一个类型参数,比如模板参数T,然后只比较类型为T的元素,或者用户提供的比较函数能够处理类型转换。 现在,综合这些思考,可以开始编写代码结构。首先,FlexibleList的节点结构: struct Node { std::any data; Node* prev; Node* next; Node(const std::any& d, Node* p = nullptr, Node* n = nullptr) : data(d), prev(p), next(n) {} }; 然后,FlexibleList类包含头指针,以及大小等信息。插入操作如push_back: void push_back(const std::any& value) { Node* newNode = new Node(value, tail, nullptr); if (tail) { tail->next = newNode; } else { head = newNode; } tail = newNode; ++size; } 删除操作如pop_back: void pop_back() { if (tail) { Node* temp = tail; tail = tail->prev; if (tail) { tail->next = nullptr; } else { head = nullptr; } delete temp; --size; } } 然后,迭代器类FlexibleIterator需要包含当前节点的指针,并重载operator++,operator--等: class FlexibleIterator { public: using iterator_category = std::bidirectional_iterator_tag; using value_type = std::any; using difference_type = std::ptrdiff_t; using pointer = std::any*; using reference = std::any&; FlexibleIterator(Node* node = nullptr) : current(node) {} reference operator*() const { return current->data; } pointer operator->() const { return &current->data; } FlexibleIterator& operator++() { current = current->next; return *this; } FlexibleIterator operator++(int) { FlexibleIterator temp = *this; ++(*this); return temp; } // 类似实现operator--, ==, != private: Node* current; }; 然后,AdvancedSort可能需要使用归并排序,递归分割链表,合并两个已排序的部分。由于链表是双向的,可以高效地进行分割和合并。比较函数作为参数传入: template<typename Compare> void AdvancedSort(FlexibleIterator begin, FlexibleIterator end, Compare comp) { // 实现归并排序 } 用户使用时,可以传入自定义的比较函数,处理std::any的类型转换: auto comp = [](const std::any& a, const std::any& b) { return std::any_cast<int>(a) < std::any_cast<int>(b); }; AdvancedSort(list.begin(), list.end(), comp); 不过,如果链表中存在非int类型的元素,这里会抛出异常。因此,用户需要确保比较的元素类型正确,或者在比较函数中添加类型检查。 最后,内存管理需要在FlexibleList的析构函数中释放所有节点: ~FlexibleList() { Node* current = head; while (current) { Node* next = current->next; delete current; current = next; } } 总结,实现的关键点包括:使用std::any存储动态类型,正确管理双向链表的节点,实现符合STL标准的迭代器,以及归并排序算法的应用。同时,需要处理类型安全和比较函数的设计问题。</think>### 分步实现指南 #### 一、FlexibleList双向链表容器 --- **1. 数据结构设计** 使用模板类结合`std::any`实现动态类型存储,节点结构定义如下: ```cpp struct Node { std::any data; Node* prev; Node* next; Node(const std::any& d, Node* p = nullptr, Node* n = nullptr) : data(d), prev(p), next(n) {} }; ``` **2. 核心操作实现** - **插入操作**:支持头和指定位置插入 ```cpp void push_back(const std::any& value) { Node* newNode = new Node(value, tail, nullptr); if (tail) tail->next = newNode; else head = newNode; tail = newNode; ++size; } ``` - **删除操作**:通过迭代器定位实现高效删除 ```cpp iterator erase(iterator pos) { Node* target = pos.ptr; if (target->prev) target->prev->next = target->next; else head = target->next; if (target->next) target->next->prev = target->prev; else tail = target->prev; delete target; --size; return iterator(target->next); } ``` - **内存管理**:通过析构函数递归释放内存 ```cpp ~FlexibleList() { while (head) { Node* temp = head; head = head->next; delete temp; } } ``` #### 二、AdvancedSort排序算法 --- **1. 算法选择** 采用归并排序算法实现$O(n \log n)$时间复杂度,适合链表结构: ```cpp template<typename Compare> void AdvancedSort(FlexibleIterator begin, FlexibleIterator end, Compare comp) { if (begin == end || std::next(begin) == end) return; auto mid = split(begin, end); AdvancedSort(begin, mid, comp); AdvancedSort(mid, end, comp); merge(begin, mid, end, comp); } ``` **2. 类型处理** 通过`typeid`和`any_cast`实现类型检查: ```cpp bool compareInt(const std::any& a, const std::any& b) { if (a.type() != typeid(int) || b.type() != typeid(int)) throw std::bad_any_cast(); return std::any_cast<int>(a) < std::any_cast<int>(b); } ``` #### 三、FlexibleIterator迭代器 --- **1. 迭代器类别定义** 满足双向迭代器要求: ```cpp class FlexibleIterator { public: using iterator_category = std::bidirectional_iterator_tag; using value_type = std::any; using difference_type = std::ptrdiff_t; using pointer = std::any*; using reference = std::any&; }; ``` **2. 运算符重载** 支持范围for循环的关键实现: ```cpp reference operator*() const { return current->data; } FlexibleIterator& operator++() { current = current->next; return *this; } bool operator!=(const FlexibleIterator& other) const { return current != other.current; } ``` #### 四、应用示例 --- **1. 基础操作演示** ```cpp FlexibleList list; list.push_back(42); // 存储整型 list.push_back("text"); // 存储字符串 auto it = list.begin(); std::cout << std::any_cast<int>(*it); // 输出: 42 ``` **2. 高级排序应用** ```cpp AdvancedSort(list.begin(), list.end(), [](auto& a, auto& b) { return std::any_cast<int>(a) < std::any_cast<int>(b); }); ``` **3. 迭代器遍历** ```cpp for (const auto& elem : list) { if (elem.type() == typeid(int)) std::cout << std::any_cast<int>(elem); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值