// chapter-12.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include
#include
#include
#include //包含智能指针,同时包含allocator类
#includepush_back(t); }
void pop_back() { check(0, "Empty on Stu_Info!"); data->pop_back(); }
string &front()const { check(0, "Empty on Stu_Info!"); return data->front(); }
string &back()const { check(0, "Empty on Stu_Info!"); return data->back(); }
private:
shared_ptr> data = make_shared>(); //需要值初始化。shared_ptr创建对象需要初始化,否则类函数无法运行!
void check(vector::size_type i,const string &msg) const //自己设计容器类,需要设计check函数,保证在每步操作时检查是否越界!
{
if (i >= data->size())
throw out_of_range(msg);
}
};
class Stu_InfoPtr
{
public:
Stu_InfoPtr():curr(0){}
Stu_InfoPtr(Stu_Info &a,size_t sz=0):wptr(a.data),curr(sz){}
string &deref() const;
Stu_InfoPtr &incr();
private:
weak_ptr> wptr;
size_t curr;
shared_ptr> check(size_t i, const string &msg)const;//const成员函数,不可以修改对象,只能调用const函数!
};
shared_ptr> Stu_InfoPtr::check(size_t i, const string &msg) const //将weak_ptr绑定到类中shared_ptr智能指针,通过weak_ptr判断对象是否存在,如果存在则返回其智能指针!(核查指针类)
{
auto ret = wptr.lock();
if (!ret)
throw runtime_error("unbound stu_info!");
if (i >= ret->size())
throw runtime_error(msg);
return ret;
}
string &Stu_InfoPtr::deref()const
{
auto p = check(curr, "err!");
return (*p)[curr];
}
Stu_InfoPtr &Stu_InfoPtr::incr()
{
check(curr, "err!");
++curr; //递增下标!
return *this;
}
unique_ptr clone_int(int p)
{
unique_ptr ret(new int(p));
return ret;
}
int main()
{
//shared_ptr和unique_ptr都支持的操作
//shared_ptr sp; 初始化,空智能指针!
//unique_ptr up;
//p 将p用作条件,若p指向对象则为true
//*p 解引用,得到对象
//p->mem
//p.get() 返回p中所保存的指针!若智能指针释放了对象,则返回指针所指向的对象也就消失了!切记代码不能delete返回的指针!也不要用返回的指针初始化另一个智能指针!
//swap(p,q) 交换p和q的指针!
//p.swap(q)
//shared_ptr独占的操作
//make_shared(args) 返回shared_ptr,使用args初始化对象
//shared_ptr p(q) p是q的拷贝,会增加q中的use_count()值,指向同一个对象!
//p=q
//p.unique() 若p.use_count()为1,返回true,否则返回false
//p.use_count() 与p共享对象的只能指针数量,主要应用于调试!(当其为0时,自动销毁对象,并释放内存)
//如果将shared_ptr存放在一个容器中,而后不再需要全部容器,要记得用erase删除不再需要的那些元素。(加入vector,即拷贝智能指针)
shared_ptr p1 = make_shared(10);
auto p2 = make_shared(3, '3');
auto p3(p2);
auto p4=make_shared>();
p4->push_back("abc");
//程序使用动态内存出于三个原因:1、程序不知道自己需要多少元素;2、程序不知道所需对象的准确类型;3、程序需要在多个对象间共享数据!
//class Stu_Info为多个对象间共享数据,当拷贝类时,底层数据直接共享!
Stu_Info s1;
string tmp = "aaa";
s1.push_back(tmp);
Stu_Info s2;
s2 = s1;
cout << s2.back() << endl;
//直接管理内存new和delete
int *pi1 = new int(); //值初始化为0
string *ps1 = new string; //初始化为空的string
vector *pv1 = new vector{ 1,2,3,4,5 };
const int *pi2 = new const int(1024);
const string *ps2 = new const string;
int *pi3 = new(nothrow) int(1); //当new不能分配内存时,将抛出bad_alloc错误。声明nothrow,则只返回空指针!
delete pi3; //释放非new分配的内存,或多次释放相同的指针值,其行为为定义!
delete ps2; //内置指针管理的动态内存被显示释放前会一直存在!
pi3 = nullptr;
ps2 = nullptr; //避免空悬指针!指针本身是对象,所以需要将它置为nullptr
//shared_ptr和new结合使用,当将一个shared_ptr绑定到一个普通指针时,就不应该再使用内置指针来访问对象!
//shared_ptr p(q) p管理内置指针q所指对象,q必须为new分配的内存,且类型一致!接管后,就不应该使用内置指针访问对应内存了!
//shared_ptr p(u) p从unique_ptr接管对象的所有权,将u置为空!
//shared_ptr p(q,d) d为删除器,用于当程序错误时释放自定义类型对象q(q含有直接管理的内存)。d实质为函数,定义了释放对象的行为!
//shared_ptr p(p2,d) p2为shared_ptr的拷贝!
//p.reset() 若p为唯一指向其对象的shared_ptr,reset会释放此对象!若传递了内置指针q,会令p指向q,否则会将p置为空!
//p.reset(q)
//p.reset(q,d)
auto ps_reset = make_shared("abc");
if (!ps_reset.unique()) //若多个智能指针共享对象,则制作新拷贝,再修改对象的值!
ps_reset.reset(new string(*ps_reset)); //reset参数必须为内置指针!
*ps_reset += "def";
//unique_ptr独享对象!其没有make_shared函数,必须使用new初始化!
unique_ptr pu1(new int(1314));
//unique_ptr pu2(pu2) 不支持拷贝和赋值!
//unique_ptr的操作
//unique_ptr pu1
//unique_ptr pu2 声明类型为D的可调用对象来释放指针!
//unique_ptr pu3(d)
//u=nullptr 释放u指向的对象,将u置为空
//u.release() u放弃对指针的控制权,返回指针,并将u置为空
//u.reset() 释放u指向的对象,并重新指向内置指针q
//u.reset(q)
//u.reset(nullptr)
unique_ptr pus1(new string("abc"));
unique_ptr pus2(pus1.release());
pus1.reset(pus2.release());
cout << *pus1 << endl;
//特列:可以传递unique_ptr参数和返回unique_ptr对象
int i_fun_cloned = 1314;
auto pui = clone_int(i_fun_cloned);
cout << *pui << endl;
//weak_ptr,不控制所指对象生存期的弱智能指针!
//weak_ptr w 创建空智能指针
//weak_ptr w(sp) 用shared_ptr初始化指针,或者赋值!
//w=p
//w.reset() 将w置为空
//w.use_count() 与w共享对象的shared_ptr的数量
//w.expired() 若use_count为0,则返回true
//w.lock() 如果expired()为true,则返回空shared_ptr,否则返回一个指向w对象shared_ptr
//由于对象可能不存在,所以不能使用weak_ptr直接访问对象!常用于核查指针类!
shared_ptr sps(new string("abc"));
weak_ptr wps(sps);
if (!wps.expired())
cout << *wps.lock() << endl;
//动态数组,在类中创建动态数组需要定义拷贝、赋值、析构等函数,推荐使用容器!
int *pia1 = new int[10]; //[]内必须为整型,可以不是常量!
//动态数组得到的是元素类型的指针,动态数组不能调用begin()和end()来返回首尾指针!同理,也不能使用范围for!
int *pia2 = new int[10]();
string *pis1 = new string[3]{ "a","b" };
unique_ptr upa(pia1); //不支持点和箭头运算符!
delete[]pis1;
upa.release();
//shared_ptr不支持管理动态数组,如果要使用,必须自定义删除器释放内存!另外shared_ptr不支持下标运算符,同时也不支持指针算术运算。因此必须使用get获取内置指针,再来访问元素!
//allocator类,支持内存分配和对象构造分离!
allocator alloc; //可以分配string的allocator对象
auto palloc = alloc.allocate(10); //分配n个未初始化的string
//标准库allocator的操作
//allocator a 创建对象
//a.allocate(n) 分配未构造的内存!
//a.deallocate(p,n) 释放内存!释放前必须调用destroy()。此n值必须与构造时的n值相同!
//a.construct(p,args) 在p所指向的内存上构造对象!
//a.destroy(p) 调用析构函数!
auto qalloc = palloc;
alloc.construct(qalloc++, 10, "ab");
while (qalloc !=palloc)
{
alloc.destroy(--qalloc); //只能对真正构造了元素进行destroy操作!
}
//allocator算法,在已分配内存位置构造元素
//uninitiated_copy(b,e,b2) 从be范围内元素拷贝到b2
//uninitiated_copy_n(b,n,b2) 从b指向元素开始拷贝n个元素到b2
//uninitiated_fill(b,e,t) 在迭代器b和e间创造元素,值为t
//uninitiated_fill_n(b,n,t) 创建n个对象
auto palloc_cp = alloc.allocate(10);
vector v_to_alloc = { "ab","bac" };
auto qalloc_cp = uninitialized_copy(v_to_alloc.begin(), v_to_alloc.end(), palloc_cp); //返回构造元素之后的位置!
//文本查询程序
cout << endl;
system("pause");
return 0;
}
//标准库定义了2个智能指针类型来管理动态分配的对象,当一个对象应该被释放时,指向它的智能指针可以确保自动释放它!
//c++中有new为对象分配空间,有delete接受动态对象的指针,销毁对象,释放空间!
//为了更容易使用动态内存,新标准提供智能指针,shared_ptr允许多个指针指向同一个对象,unique_ptr则独占所指向的对象,weak_ptr是弱作用,指向shared_ptr所管理的对象!