【C++ Primer 第5版 笔记】第12章 动态内存与智能指针
转载:http://blog.csdn.net/wwh578867817/article/details/41866315
shared_ptr<int> pi = make_shared<int>(25);
auto ps = make_shared<string>(10, '9');
auto r = make_shared<int>(42); //r指向的int只有一个引用者
r = q; //给赋值,r指向另一个地址//递增q指向的对象的引用计数//递减r原来指向的对象的引用计数// r原来指向的对象已经没有引用者,会自动释放
#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <stdexcept>
using namespace std;class StrBlob
{
public:typedef vector<string>::size_type size_type; StrBlob();StrBlob(initializer_list<string> il);size_type size() const {return data->size();}bool empty() const {return data->empty();}//添加和删除元素 void push_back(const string &t) {data->push_back(t);}void pop_back();//元素访问string &front();string &back(); const string &front() const;const string &back() const; private:shared_ptr<vector<string>> data; //如果data[i]不合法,抛出一个异常 void check(size_type index, const string &msg) const;
};//默认构造函数
StrBlob::StrBlob() : data(make_shared<vector<string>>()) {}//拷贝构造函数
StrBlob::StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>()) {}void StrBlob::check(size_type index, const string &msg) const
{if(index >= data->size())throw out_of_range(msg);
}void StrBlob::pop_back()
{check(0, "pop_back on empty StrBlob");data->pop_back();
}const string &StrBlob::front() const
{check(0, "front on empty StrBlob");return data->front();
}string &StrBlob::front()
{const auto &s = static_cast<const StrBlob*>(this)->front();return const_cast<string &>(s);
}const string &StrBlob::back() const
{check(0, "back on empty StrBlob");return data->back();
}string &StrBlob::back()
{const auto &s = static_cast<const StrBlob*>(this)->back();return const_cast<string &>(s);
}int main()
{ std::shared_ptr<StrBlob> sp; StrBlob s1({"wang","wei","hao"}); StrBlob s2(s1);//共享s1内的数据 std::string st = "asd"; s2.push_back(st); //s2.front(); std::cout << s2.front() << std::endl; std::cout << s2.back() << std::endl; std::cout << s1.front() << std::endl; std::cout << s1.back() << std::endl;
}
结果:
#include <iostream>
#include <string>
#include <vector> using namespace std; int main()
{ //在自由空间分配的内存是无名的,因此new无法为其分配的对象命名,而是返回一个指向该对象的指针。 int *p = new int; int *p2 = new int(10); string *p3 = new string(10,'a'); vector<string> *p4 = new vector<string>{"a","b","c"}; //也可以对动态分配的对象进行值初始化,只需在类型名之后加一对空括号 string *p5 = new string(); //值初始化 string *p6 = new string; //默认初始化 int *p7 = new int; //但是对于内置类型是未定义的。*p7值未定义 //对动态分配的对象进行初始化通常是个好主意。 //auto auto p8 = new auto("abc"); //p8指向一个与obj类型相同的对象 auto p9 = new auto{1,2,3}; //error:括号中只能有单个初始化器 //const //一个动态分配的const对象必须进行初始化。 const string *p10 = new const string("aha"); const int pci = new const int(1024); //内存耗尽 int *p11 = new int; //如果分配失败,new会抛出一个std::bad_alloc int *p12 = new (nothrow) int; //如果分配失败返回一个空指针。 bad_alloc和nothrow定义在#include <new>
}
#include <memory>
#include <iostream> using namespace std; int main()
{ //p也指向p2指向的内存,那么p原来所指向的内存区域就没有其他指针指向了,也没有释放,内存泄漏 int *p = new int(20); int *p2 = new int(40); p = p2; //p3也指向p4所指向的内存,但是p3原先指向的内存区域计数器变为0时,内存自动会释放。 auto p3 = make_shared<int>(20); auto p4 = make_shared<int>(30); p3 = p4;
}
shared_ptr<int> p1 = new int(1024); //错误:必须使用直接初始化形式
shared_ptr<int> p2(new int(1024)); //正确:使用了直接初始化形式
shared_ptr<int> clone(int p) {
return new int(1024); //错误:不能进行普通指针到智能指针的隐式转换
}shared_ptr<int> clone(int p) {
return shared_ptr<int>(new int(1024)); //正确:需要显示绑定到智能指针
}
{ auto p = make_shared<int>(20); auto q = p.get(); delete q;
}
if(!p.unique())
{
p.reset(new string(*p));
*p += newVal;
}
void f()
{shared_ptr<int> sp(new int(42)); //分配一个新对象//这段代码抛出一个异常,且在f中未被捕获//在函数结束时,shared_ptr能自动释放内存
}
connection connect(destination *);
void disconnect(connection);
void f(destination &d)
{ connection c = connect(&d); //使用连接...disconnect(d);//如果没有调用disconnect,那么永远不会断开连接。
}
connection connect(destination *);
void disconnect(connection);
void end_connection(connection *p) {disconnect(*p);}
void f(destination &d)
{ connection c = connect(&d); shared_ptr<connection> p(&c, end_connection); //使用连接//f退出时,会自动调用end_connection。
}
#include <iostream>
#include <string>
#include <memory>using namespace std;
typedef string connection;connection &connect(connection *s)
{cout << "正在建立连接..." << endl;s = new connection("connect");return *s;
}void disconnect(connection *s)
{cout << "正在断开连接..." << endl;
}int main()
{connection p;connection *dis;p = connect(dis);shared_ptr<connection> sp(&p, disconnect);
}
#include <iostream>
#include <string>
#include <memory>
#include <functional>
#include <algorithm> using namespace std;
typedef string connection; connection& connect(connection *s)
{ cout << "正在连接..." << endl; s = new connection("connect"); return *s;
} void disconnect(connection *s)
{ cout << "正在断开连接..." << endl;
} int main()
{ connection p; connection *d; p = connect(d); //shared_ptr<connection>sp(&p,disconnect); //error:lambda代表了删除函数。那么参数列表也要和删除函数一致,因为delete内部是free(p)。 //shared_ptr<connection>sp(&p, [&p] { disconnect(&p); }); shared_ptr<connection>sp(&p, [](connection *s) { disconnect(s); });
}
shared_ptr 的传递删除器(deleter)方式比较简单, 只需要在参数中添加具体的删除器函数名, 即可; 注意是单参数函数;
#include <memory>
#include <iostream>
#include <string> using namespace std; unique_ptr<int> clone(int p)
{ unique_ptr<int> q(new int(p)); //手动new,并绑定 return q;
} int main()
{ unique_ptr<string> p(new string("aaa")); shared_ptr<string> p2(new string("aaa")); //unique_ptr<string> p3(p); error:不能拷贝 //unique_ptr<string> p4 = p; error:不能赋值 unique_ptr<string> p5; string s = "a"; //p5.reset(&s); error:两次释放 //两种转移所有权的方法 unique_ptr<string> p6(p.release()); //p.release(),释放p对指针对象的控制权,返回指针并将p置空,并不会释放内存 unique_ptr<string> p7; p7.reset(p6.release()); //p6释放控制权,p7指向这个对象。 //特殊的拷贝和赋值 int i = 10; clone(i);
}
在早的版本中提供了auto_ptr的类,它有unique_ptr 的部分特性,但是不能在容器中保存auto_ptr, 也不能在函数中返回 auto_ptr, 编写程序时应该使用unique_ptr.
#include <memory>
#include <iostream> using namespace std; typedef int connection; connection *connect(connection *d)
{ cout << "正在连接..." << endl; d = new connection(40); return d;
} void disconnect(connection *p)
{ cout << "断开连接..." << endl;
} int main()
{ connection *p,*p2; p2 = connect(p); cout << p << endl; cout << *p2 << endl; unique_ptr<connection, decltype(disconnect)*> q(p2, disconnect); //在尖括号中提供类型,圆括号内提供尖括号中的类型的对象。 //使用decltype()关键字返回一个函数类型,所以必须添加一个*号来指出我们使用的是一个指针
}
auto p = make_shared<int>(42);
weak_ptr<int> wp(p); //wp若共享p:p的引用计数未改变if(shared_ptr<int> np = wp.lock())
{//如果np不为空,则成立//在if中,np和p共享对象
}
/*
*避免拷贝,多个指针共用一个vector<string>
*使用weak_ptr访问共享的对象
* */#include <iostream>
#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <stdexcept>
#include <fstream>
#include <sstream> class StrBlob;
class StrBlobPtr;class StrBlob
{
public:friend class StrBlobPtr;typedef std::vector<std::string>::size_type size_type;StrBlob(); //默认构造函数 StrBlob(std::initializer_list<std::string>il); //拷贝构造函数 size_type size() { return data->size(); } //对data进行解引用就是对vector<string>操作 std::string& front();std::string& back();const std::string& front()const;const std::string& back()const;void push_back(const std::string &s) { data->push_back(s); }void pop_back();//StrBlobPtr begin() { return StrBlobPtr(*this); } //StrBlobPtr end() { auto ret = StrBlobPtr(*this, data->size()); // return ret; } private:void check(size_type sz, std::string msg) const;std::shared_ptr<std::vector<std::string>> data;
};std::string& StrBlob::front()
{const auto &s = static_cast<const StrBlob*>(this)->front();return const_cast<std::string&>(s);
}std::string& StrBlob::back()
{const auto &s = static_cast<const StrBlob*>(this)->back();return const_cast<std::string&>(s);
}const std::string& StrBlob::front()const
{check(0, "front on empty vector");return data->front();
}const std::string& StrBlob::back()const
{check(0, "back on empty vector");return data->back();
}void StrBlob::check(size_type sz, std::string msg)const
{if (sz >= data->size())throw std::out_of_range(msg);
}StrBlob::StrBlob() :
data(std::make_shared<std::vector<std::string>>()) { }StrBlob::StrBlob(std::initializer_list<std::string> il) :
data(std::make_shared<std::vector<std::string>>(il)) { }/* --------------------------------------------------------------------------------- *///必须定义在StrBlobPtr的后面
//否则error: invalid use of incomplete type ‘class StrBlob’
class StrBlobPtr
{
public:friend StrBlob;StrBlobPtr() :curr(0){ }StrBlobPtr(StrBlob &s, std::size_t sz = 0) :wptr(s.data), curr(sz){ }std::string& deref()const; //返回当前string StrBlobPtr& incr(); //递增 private:std::shared_ptr<std::vector<std::string>> check(std::size_t i, const std::string &msg)const;std::weak_ptr<std::vector<std::string>> wptr;std::size_t curr; //当前下标
};StrBlobPtr& StrBlobPtr::incr()
{check(curr, "increment past end of StrBlobPtr");++curr; //推进当前位置。 return *this; //为什么要return *this, 如果再次自加可以重复,举个例子就像赋值一样 a = b = c; 如果不返回对象不能继续赋值。
} //return *this是一份拷贝。 return this是地址。 std::string& StrBlobPtr::deref()const
{auto p = check(curr, "dereference past end"); //shared_ptr引用计数会增加,但是作用域结束后,引用计数又会减1 return (*p)[curr]; //p是所指的vector
}//check检查是否存在shared_ptr和大小
std::shared_ptr<std::vector<std::string>> StrBlobPtr::check(std::size_t i, const std::string &msg)const
{auto ret = wptr.lock(); //检查是否存在,存在返回shared_ptr,不存在返回空的shared_ptr. if (!ret)throw std::runtime_error("unbound StrBlobPtr");if (i >= ret->size())throw std::out_of_range(msg);return ret;
}int main(int argc, char*argv[])
{std::fstream is(argv[1]);std::string s;StrBlob S;while (std::getline(is, s)){std::string temp;std::istringstream ist(s);while (!ist.eof()){ist >> temp;S.push_back(temp);}}std::cout << "size:" << S.size() << std::endl;StrBlobPtr sp(S);for (auto i = 0; i < S.size(); ++i){std::cout << sp.deref() << std::endl;sp.incr();}
}
- #include <iostream>
- #include <memory>
- using namespace std;
- typedef int arr[10];
- int main()
- {
- int *p = new int[10];
- int *p2 = new arr;
- for(int i = 0; i < 10; i++)
- {
- p[i] = i;
- }
- for(int i = 0; i < 10; i++)
- cout << p[i] << " ";
- cout << endl;
- //for(const int i : p); //error:动态分配数组返回的不是数组类型,而是数组元素的指针。所以不能用范围for
- /*---------------------------------- */
- //初始化动态数组
- int *pi = new int[10]; //未初始化
- int *pi2 = new int[10](); //初始化为0,且有括号必须为空
- string *ps = new string[10]; //10个空string
- string *ps2 = new string[10](); //10个空string
- //可以使用列表初始化
- int *pi3 = new int[10]{1,2,3,4,5,6,7,8,9,0};//初始值列表里的值不能多于容量,否则new失败,不会分配内存
- string *ps3 = new string[10]{"a","b","c","d","e","f","g","h","i",string(3,'x')};
- //释放动态数组
- delete []pi3; //必须要加[]括号,且释放动态数字时是逆序释放。如果delete动态数组不加[],行为是未定义的。
- /*----------------------------------- */
- //智能指针和动态数组,标准库定义了特别的unique_ptr来管理,当uo销毁它管理的指针时,会自动调用delete [];
- int *p5 = new int[10];
- //unique_ptr<int[]> up;
- unique_ptr<int[]> up(p5);
- for(int i = 0; i < 10; ++i)
- cout << up[i] << " ";
- cout << endl;
- //如果使用shared_ptr的话我们必须自己定义delete函数
- shared_ptr<int>sp(new int[10], [](int *p) { delete []p;});
- //智能指针不支持算数类型,如果要访问数组中的元素,必须使用get函数返回一个内置指针。
- cout << (*sp.get()) << endl;
- }
- #include <iostream>
- #include <string>
- using namespace std;
- int main()
- {
- string s1;
- cin >> s1;
- string *p = new string(s1);
- const char *p1 = new char[s1.size()];
- p1= (*p).c_str(); //转换为一个c风格的字符串,但是是const类型的
- cout << "*p1 " << *p1 << endl; //只会输出第一个字母,说明new创建返回的不是数组类型的指针,而是元素类型
- cout << "p1 ";
- for(int i = 0; i < s1.size(); ++i)
- cout << p1[i] << " ";
- cout << endl;
- const char *p2 = new char[10];
- string ss;
- ss = "aaaaaaaaaaaaaaaaaaaaaa"; //超出了动态分配的内存空间
- p2 = ss.c_str();
- cout << "p2 ";
- for(int i = 0; i < ss.size(); ++i) //结果还是正常输出了!
- cout << p2[i] << " ";
- cout << endl;
- }
- #include <iostream>
- #include <memory>
- #include <string>
- using namespace std;
- int main()
- {
- //allocator<T>a; 定义了一个名为a的allocator对象,可以为T对象分配空间
- allocator<string>alloc;
- //a.allocate(n); 为T分配n个空间
- string *const p = alloc.allocate(10); //为10个string分配了内存,且内存是原始的,未构造的
- cout << sizeof(p) << endl;
- //释放p中地址的内存,这快内存保存了n个T对象,p必须是allocte返回的指针,n必须是allocate(n)的n
- //且在调用deallocate时必须先毁坏这块内存中创建的对象
- alloc.deallocate(p,10);
- //p是allocate返回的指针,construction是传递给类型T的构造函数,在p指向的内存中构造一个对象
- //alloc.construct(p, construction)
- //对p指向的对象进行析构函数。
- //alloc.destroy(p);
- allocator<string>alloc2;
- auto const p2 = alloc2.allocate(10);
- auto q = p2;
- auto q2 = p2;
- //为了使用我们allocate的内存,必须用construct构造对象,使用未定义的内存,其行为是未定义的。
- alloc2.construct(q++, "sssss");
- cout << *q2++ << endl;
- alloc2.construct(q++, "he");
- cout << *q2++ << endl;
- alloc2.construct(q++, 10, 'x');
- cout << *q2 << endl;
- //对使用过的内存进行释放,调用string的析构函数,注意不能destory未使用的内存。
- while(q2 != p2)
- alloc2.destroy(q2--);
- //元素被销毁后,我们可以重新使用这块内存,也可以归还给系统
- alloc2.deallocate(p2, 10);
- //deallocate的指针不能为空,必须指向allocate分配的内存,且deallocate和allocate的大小相同。
- }
- uninitialized_copy(b,e,b2) b,2是输入容器的迭代器,b2是内存的起始地址,要保证空间足够
- uninitialized_copy_n(b,n,b2) b是输入容器的起始迭代器,复制n个,复制到以b2为起始地址的动态内存中
- uninitialized_fill(b,e,t) b,e是动态内存的起始和终止位置,t是要fill的元素
- uninitialized_fill_n(b,n,t) b是动态内存的起始,fill n个,t是要fill的元素
- #include <iostream>
- #include <string>
- #include <vector>
- #include <memory>
- using namespace std;
- int main()
- {
- //copy返回的是最后一个元素的下一个位置,fill返回void
- vector<string>ivec(10,"a");
- allocator<string>alloc;
- auto const p = alloc.allocate(ivec.size()*4);
- auto q = uninitialized_copy(ivec.begin(),ivec.end(), p);
- auto q2 = q;
- while(q-- != p)
- cout << *q << " ";
- cout << endl;
- uninitialized_fill_n(q2, ivec.size(), "b");
- for(auto i = 0; i < ivec.size(); ++i)
- cout << *q2++ << " ";
- cout << endl;
- vector<string>ivec2(10,"c");
- auto q3 = uninitialized_copy_n(ivec2.begin(),10,q2);
- for(auto i = 0; i < ivec2.size(); ++i)
- cout << *q2++ << " ";
- cout << endl;
- uninitialized_fill(q3,q3+10, "d");
- for(auto i = 0; i < ivec2.size(); ++i)
- cout << *q3++ << " ";
- cout << endl;
- }
【C++ Primer 第5版 笔记】第12章 动态内存与智能指针相关推荐
- 12.1 动态内存与智能指针(2)
今天继续学习12.1节时,从练习12.17中发现了一个问题. 首先摘录教材中的原话--一个unique_ptr"拥有"它所指向的对象.与shared_ptr不同,某个时刻只能有一个 ...
- 《C Primer Plus》学习笔记—第12章
目录 <C Primer Plus>学习笔记 第12章 存储类别.链接和内存管理 1.存储类别 1.作用域 2.链接 3.存储期 4.自动变量 1.程序hiding.c 2.没有花括号的块 ...
- C++ Primer 5th笔记(chap 12 动态内存)智能指针概述
1. 对象的生存期 内存类型 定义 分配和销毁时机 全局对象 程序启动时分配,程序结束时销毁 静态内存 局部static对象类static数据成员 第一次使用时分配,程序结束时销毁 栈内存 定义在函数 ...
- 《C Primer Plus》学习笔记—第9章
目录 <C Primer Plus>学习笔记 第9章 函数 1.复习函数 1.引入 2.创建并使用简单的函数:程序lethead1.c 3.分析程序 4.函数参数 1.程序lethead2 ...
- 《C Primer Plus》学习笔记—第14章
目录 <C Primer Plus>学习笔记 第14章 结构和其他数据形式 1.示例问题:创建图书目录 1.程序book.c 2.建立结构声明 3.定义结构变量 1.初始化结构 2.访问结 ...
- 梓益C语言学习笔记之链表&动态内存&文件
梓益C语言学习笔记之链表&动态内存&文件 一.定义: 链表是一种物理存储上非连续,通过指针链接次序,实现的一种线性存储结构. 二.特点: 链表由一系列节点(链表中每一个元素称为节点)组 ...
- 计算机网络第七版笔记--第三章
计算机网络第七版学习笔记 第三章数据链路层 3.1使用点对点信道的数据链路层 3.1.1数据链路和帧 1.链路(link)就是从一个结点到相邻结点的一段物理线路(有线或无线),而中间没有任何其他的交换 ...
- Real-time Rendering (3rd edition)学习笔记第1-2章
本博文仅作学习使用,欢迎学习渲染和计算机图形学的朋友相互讨论. 目录 第1章 介绍 1.1 内容概括 1.2 符号和定义 1.2.1 数学符号 1.2.2 几何定义 进一步阅读和参考资料 第2章 图形 ...
- python基础课程第12章_流畅的python学习笔记-第12章
第12章-类继承 super函数 Py 2.x 和 Py 3.x 中有一个很大的区别就是类,无论是类的定义还是类的继承. Py 3.x 中类的继承可以直接使用 super() 关键字代替原来的 sup ...
最新文章
- Android开发之使用Handler封装下载图片工具类(源代码分享)
- 浅析网络营销外包中如何实现网络营销外包中的图片推广?
- CodeForces - 1537E2 Erase and Extend (Hard Version)(扩展KMP-比较两个前缀无限循环后的字典序大小)
- 一件重要的事想要告诉大家
- 如何修改 pdf 文件默认的显示图标
- 如何恢复右键里新建记事本
- BZOJ1853: [Scoi2010]幸运数字(容斥原理)
- vscode安装vetur不高亮解决
- php sqlite创建表,php – 使用SQLite创建列表树
- python和前端(三)JS的激情
- 程序员数学(7)--平面直角坐标系
- 《整理的艺术》x《简约至上》
- 2020暨南大学计算机专硕考研经验分享
- Riverbed助力Interplex成功使用机器人技术
- 网络安全笔记-99-渗透-SSRF
- matlab中二维插值中cubic方法的实现原理(个人见解)
- linux 下文件防篡改,Rsync+inotify实现文件防篡改
- ip地址转换htonl的用法
- 令人拍案叫绝的算法学习网站新手算法入门到精通,算法面试冲刺资料这里都有
- 中国推出网上“防沉迷系统”
热门文章
- 云计算服务商中云融信 十一月产品升级
- 7-6 到底是不是太胖了 (10分)
- web 渗透【4】脚本马的制作与原理
- html中点击左边菜单右边内容切换
- (7)达梦DMDSC数据共享集群核心技术原理介绍
- 【转】OLEDB和ODBC以及ADO最形象的解释
- 计算机B的IP地址是,一个B类IP地址172.16.1.0,划分八个子网,计算分配各子网有效地址和最大计算机数...
- 201、基于51单片机智能窗帘设计多功能自动手动定时光控遥控红外防盗窗帘控制系统
- Windows服务器实现文件监控实时同步
- python程序设计教程张莉课后答案_清华大学出版社-图书详情-《Visual Basic程序设计教程》...