c++ set容器存储指针,智能指针用法
Set容器存储c++内置变量
set容器存储基础变量像int,char,或者是string对象,我们不需要去写比较函数,但是如果存储的是自定义类对象或者是结构体,那就需要重载<运算符或者重载(),在构造set容器时作为第二个参数传入,set容器存储内置变量,我就不记录了,这篇文章主要讲存储类对象以及用指针或者智能指针存储的用法
Set容器存储指向类对象的智能智能对象
我们知道stl存储对象时有一个特点,就是其实是对对象进行拷贝,然后存储,同时如果声明的是基类对象,而实际插入时是子类对象,那和子类相关的成员变量和函数就会被剥离,也就是不支持多态.所以我们一般选择存储指针,但是由于存储普通指针时,stl容器会对指针和指针指向的内存也进行拷贝,所以容器只会对它拷贝的那个指针变量指向的内存进行管理,而之前的内存需要我们自己去释放,所以使用智能指针就是最佳的选择.至于使用shared_ptr还是unique_ptr,这里需要根据自己需求来选,他们的区别,可以自己去了解,我只写使用shared_ptr的示例:
#include <iostream>
#include <set>
#include <memory>
#include <functional>
#include <unordered_set>
using namespace std;
namespace set_test
{
struct song
{
int m_id;
int m_hot;
song(int id, int hot)
{
this->m_id = id;
this->m_hot = hot;
}
~song() {
cout << "~song:m_id=" << m_id << ",m_hot=" << m_hot << endl;
}
//set容器中存放类对象时,自定义比较函数方式1:内部重载<
bool operator<(const struct song & right)const //重载<运算符
{
if (this->m_id == right.m_id) //根据id去重
return false;
else
{
if (this->m_hot != right.m_hot)
{
return this->m_hot > right.m_hot; //降序
}
else
{
return this->m_id > right.m_id;
}
}
};
//set容器中存放类对象智能指针时,自定义比较函数方式1:friend方式重载<
friend bool operator <(const shared_ptr< song>& left, const shared_ptr< song>& right)
{
//return false;
if (left->m_id == right->m_id) //根据id去重
return false;
else
{
if (left->m_hot != right->m_hot)
{
return left->m_hot < right->m_hot; //降序
}
else
{
return left->m_id < right->m_id;
}
}
}
};
//set容器中存放类对象时,自定义比较函数方式2:指定set_comp为函数对象(必须申明为const引用)
struct set_comp
{
bool operator()(const struct song& left, const struct song& right) //重载()运算符
{
if (left.m_id == right.m_id) //根据id去重
return false;
else
{
if (left.m_hot != right.m_hot)
{
return left.m_hot > right.m_hot; //降序
}
else
{
return left.m_id > right.m_id;
}
}
}
};
//set容器中存放类对象智能指针时,自定义比较函数方式2:指定set_share_ptr_compptr为函数对象(必须申明为const引用)
struct set_share_ptr_compptr
{
bool operator()(const shared_ptr <song>& left, const shared_ptr<song>& right) //重载()运算符
{
if (left->m_id == right->m_id) //根据id去重
return false;
else
{
if (left->m_hot != right->m_hot)
{
return left->m_hot > right->m_hot; //降序
}
else
{
return left->m_id > right->m_id;
}
}
}
};
void print_set(std::set<shared_ptr< song>>& prSet)
{
for (auto& it : prSet)
{
std::cout << "id:" << it->m_id << ",hot:" << it->m_hot << endl;
}
}
//set存储类对象
void test1()
{
cout << "set存储类对象,使用类成员函数作为比较函数:" << endl;
std::set<song> mySet; //使用重载的<
auto s1 = song(10, 100);
auto s2 = song(20, 200);
auto s3 = song(20, 300);//重复的插不进
auto s4 = song(40, 300);
auto s5 = song(50, 200);
auto s6 = song(60, 400);
auto s7 = song(50, 300);
mySet.insert(s1); //插入s1
mySet.insert(s2); //插入s2
mySet.insert(s3); //s3和s2的id相同,不插入
mySet.insert(s4); //插入s4
mySet.insert(s5); //s5 m_hot比s4 m_hot小在s4后面
mySet.insert(s6); //s6 m_hot比s4 m_hot大在s4前面
mySet.insert(s7); //s7 m_hot和s4 一样大,但是s7 m_id比s4 m_id大,
cout << "set存储类对象,使用函数对象作为比较函数:" << endl;
std::set<song, set_comp> mySet1; //使用外部定义的的()
for (auto&val : mySet)
{
mySet1.emplace(val);
}
}
//set存储智能指针
void test2()
{
cout << "set存储类对象智能指针,使用类成员函数作为比较函数:" << endl;
std::set<shared_ptr< song>> mySet; //使用重载的<
auto s1 = std::make_shared<song>(10, 100);
auto s2 = std::make_shared<song>(20, 200);
auto s3 = std::make_shared<song>(20, 300);//重复的插不进
auto s4 = std::make_shared<song>(30, 300);
auto s5 = std::make_shared<song>(40, 200);
auto s6 = std::make_shared<song>(40, 200);//重复的插不进
auto s7 = std::make_shared<song>(50, 400);//重复的插不进
mySet.insert(s1); //插入s1
mySet.insert(s2); //插入s2
mySet.insert(s3); //s3和s2的id相同,不插入
mySet.insert(s4); //插入s4
mySet.insert(s5); //插入s5,看和s4是如何排序的
mySet.insert(s6); //看是否插的进
mySet.insert(s7); //看是否插的进
//输出一次
print_set(mySet);
//修改一个值,再看输出
for (auto &info : mySet)
{
if (info->m_id == 10)
{
info->m_hot = 1000;
break;
}
}
cout << "修改后输出" << endl;
std::set<shared_ptr< song>> mySet1; //使用重载的<
mySet.swap(mySet1);
//输出一次
print_set(mySet);
print_set(mySet1);
cout << "修改后再插入新值:" << endl;
mySet1.insert(std::make_shared<song>(60, 600));
print_set(mySet1);
/*
修改容器对象成员变量值,不会引起重新排序,即使插入新值也只是新值进行排序,被修改的值不会排序
*/
cout << "set存储类对象智能指针,使用函数对象作为比较函数:" << endl;
std::set<shared_ptr< song>, set_share_ptr_compptr> mySet2; //使用外部定义的的()
for (auto&val : mySet1)
{
mySet2.emplace(val);
}
}
//测试遍历一个set删除另外一个set中的元素
void test3()
{
set < shared_ptr<song>> set1, set2;
for (int i = 0; i < 10; i++)
{
set1.insert(make_shared<song>(i, i * 10));
}
for (auto& str : set1)
{
set2.insert(str);
}
//删除第一个
set2.erase(*(set1.begin())); //用元素关键值删除
set2.erase(set2.begin());//用迭代器删除
//遍历set2,删除set1中的元素
for (auto it = set2.begin(); it != set2.end();)
{
set1.erase(*it);
if ((*it)->m_id != 9)
{
set2.erase(it++);//迭代器先加再删除
//it = set2.erase(it);//等价于上面那种写法
}
else
{
it++;
}
}
//因为自定义了比较函数,比较函数中当m_id相同时就可以判断是同一个元素,所以可以通过构建临时对象来删除;
set2.erase(make_shared<song>(9, 90));
}
void test_all()
{
test1();
test2();
test3();
};
}