动态内存
作者:互联网
#include<iostream>
#include<string>
#include<vector>
#include<numeric>
#include<list>
#include<functional>
using namespace std;
/*
到目前为止,我们使用的对象都有严格的生存期,全局对象在程序启动时分配,在程序结束时销毁
对于局部自动对象,当我们进入其定义所在的程序块时被创建,在离开块时 被销毁,局部static
对象在第一次使用前分配,在程序结束时销毁
*/
//静态内存用来保存局部static对象,类static数据成员,以及定义在任何函数之外的变量
//栈内存用来保存定义在函数内的非static对象
//内存池,部分内存被称作自由空间或堆,程序用堆来存储动态分配的对象
//shared_ptr:允许多个指针指向同一个对象
void test01() {
shared_ptr<string>p1; //可以指向string
shared_ptr<list<int>>p2; //可以指向int的list
//默认初始化的智能指针保存着一个空指针,对智能指针解引用可以返回它指向的对象
if (p1 && p1->empty())
*p1 = "h1";
//make_shared函数(定义在memory中)
shared_ptr<int>p3 = make_shared<int>(42);
shared_ptr<string>p4 = make_shared<string>(10, 'a');
shared_ptr<int>p5 = make_shared<int>();
//p6指向一个动态分配的空vector<string>
auto p6 = make_shared<vector<string>>();
//shared_ptr的拷贝和赋值
//当进行拷贝和赋值时,每个shared_ptr都会记录有多少个其他的shared_ptr指向相同的对象
auto p = make_shared < int>(42); //p指向的对象只有p一个引用者
auto q(p); //p和q指向相同的对象,此对象有两个引用者
//每个shared_ptr都有一个关联的计数器,通常称其为引用计数,无论何时我们拷贝一个shared_ptr时,计数器都会递增
//当我们给shared_ptr赋予一个新的值或者是shared_ptr被销毁时,计数器就会递减
auto r = make_shared<int>(42);
r = q; //给r赋值,递增q指向对象的引用计数,递减r原来指向对象的引用计数
//shared_ptr自动销毁所管理的对象-析构函数
/*
shared_ptr的析构函数会递减它所指向对象的引用计数,如果引用计数变成0,shared_ptr的析构函数就会销毁对象,并释放它所占的内存
*/
/*
1.对于一块内存,shared_ptr类保证只要有任何shared_ptr对象引用它,它就不会被释放掉
2.如果你将shared_ptr存放于一个容器中,而后不再需要全部元素,而只是用其中的一部分,
要记得用erase删除不再需要的那些元素
*/
}
/*
使用了动态生存期的资源的类
程序使用动态内存处于下面三种原因
1.程序不知道自己需要使用多少对象
2.程序不知道所需的对象的准确类型
3.程序需要在多个对象间共享数据
*/
void test07() {
/*
我们拷贝一个vector时,原vector和副本vector中的元素是相互分离的
由一个vector分配的元素只有当这个vector存在时才存在,当一个vector被销毁时
这个vector中的元素也都被销毁
*/
vector<string>v1;
{
vector<string>v2 = { "a", "an", "the" };
v1 = v2; //从v2拷贝元素到v1中
}
//v2被销毁,其中的元素也被销毁,v三个元素是原来v2中元素的拷贝
/*
一般而言,如果两个对象共享底层的数据,当某个对象被销毁时,我们不能单方面的销毁底层数据
*/
//blog对象是一不同拷贝之间共享相同的元素的一个类
//Blob<string> b1;
//{
// Blob<string>b2 = { "a", "an", "the" };
// b1 = b2; // b1和b2共享相同的元素
//}//b2被销毁了,但是b2中的元素不能被销毁
}
//数据共享类
class StrBlob {
public:
typedef std::vector<std::string>::size_type size_type;
StrBlob();
StrBlob(std::initializer_list<std::string>il);
size_type size() const { return data->size(); };
bool empty() const { return data->empty(); };
void push_back(const std::string & t) { data->push_back(t); };
void pop_back();
std::string& front();
std::string& back();
private:
std::shared_ptr<std::vector<std::string>>data;
void check(size_type i, const std::string& msg) const;
};
StrBlob::StrBlob() :data(make_shared<vector<string>>()) {};
StrBlob::StrBlob(initializer_list<string>il) :data(make_shared<vector<string>>(il)) {};
void StrBlob::check(size_type i, const string& msg)const {
if (i >= data->size())
throw out_of_range(msg);
}
string& StrBlob::front() {
check(0, "front on empty StrBlob");
return data->front();
}
string& StrBlob::back() {
check(0, "back on empty StrBlob");
}
void StrBlob::pop_back() {
check(0, "pop_back on empty StrBlob");
}
//直接管理内存
void test02() {
int* p1 = new int;
string* ps = new string; //ps指向为初始化的int
int* p1 = new int(1024);
string* ps = new string(10, '9');
vector<int>* pv = new vector<int>{ 0, 1, 2, 3 };
//使用auto时,由于编译器要使用初始化器的类型类推断我们要分配的类型,只有当括号中仅有单一初始器时才可以使用auto
auto p1 = new auto(10);
//auto p2 = new auto{a, b, c}; 错误,括号中只能有单个初始化器
//动态分配的const对象
const int* pci = new const int(1024);
const string* pvs = new const string;
/*
类似于其他任何const对象,一个动态分配的const对象必须进行初始化,对于一个定义了默认构造函数的类类型,
其const动态对象可以是隐式初始化,而其他类型的对象就必须显示初始化,由于分配的对象是const,new返回的指针是一个指向const的
指针
*/
//内存耗尽
int* p1 = new int; //如果分配失败,new抛出std::bad_alloc
int* p2 = new (nothrow)int; //如果分配失败,new返回一个空指针
//指针和delete
/*
1.忘记delete内存
2.使用已经释放掉的对象
3.同一块内存释放两次
delete一个指针后,该指针就变成无效了,为空悬指针
*/
int* p(new int(42));
auto q = p;
delete p; //p和q都变成无效的
p = nullptr;
//share_ptr和new结合使用
shared_ptr<double>p1;
shared_ptr<int>p2(new int(42));
//shared_ptr<int>p1 = new int(1024); 错误必须使用直接初始化
/*shared_ptr<int> clone(int p) {
return new int(p); //错误,隐式转换为shared_ptr<int>
}*/
//不要混合使用普通指针和智能指针
int* x(new int(1024)); //危险,x是一个普通指针,不是一个智能指针
//也不要使用get初始化另一个智能指针或为智能指针赋值
shared_ptr<int>p(new int(42));
int* q = p.get();
{
shared_ptr<int>q;
} //q被销毁,所指向的内部被释放了
int foo = *p; //未定义 p所指向的内存已经被释放了
//使用get将指针的访问权限传递给代码,你只有在确定代码不会delete指针的情况下,才可以使用get
//其他shared_ptr操作
shared_ptr<int>p(new int(30));
p.reset(new int(1024)); //p指向一个新的对象
if (!p.unique())
p.reset(new string(*p)); //我们不是唯一用户,分配新的拷贝
}
//传递unique_ptr参数和返回unique_ptr
unique_ptr<int>clone(int p) {
return unique_ptr<int>(new int(p));
}
unique_ptr<int>clone(int p) {
unique_ptr<int>ret(new int(p));
return ret;
}
//unique_ptr
void test03() {
unique_ptr<double>p1;
unique_ptr<int>p2(new int(42));
unique_ptr<string>p1(new string("hello"));
//unique_ptr<string>p2(p1); 错误,unique_ptr不支持拷贝
//p3 = p2; 错误unique_ptr不支持赋值
unique_ptr<string>p2(p1.release());//使用release将p1置为空
p2.reset(p2.release()); //reset释放了p2原来指向的内存,返回一个指针
}
//weak_ptr
void test04() {
auto p = make_shared < int>(42);
weak_ptr<int>wp(p); //wp弱共享p,p的引用计数未改变
}
//动态数组
void test05() {
int* pia = new int[10];
int* pia2 = new int[10]();
string* psa = new string[10];
string* psa2 = new string[10]();
delete[] pia;
typedef int arrt[42];
int* p = new arrt;
delete[] p;
//智能指针和动态数组
unique_ptr<int[]>up(new int[10]);
up.release();
//当unique_ptr指向一个数组时,可以用下标运算符来访问数组中的元素
for (size_t i = 0; i != 10; i++) {
up[i] = i;
}
//与unique_ptr不同,,shared_ptr不直接支持管理动态数组
shared_ptr<int>sp(new int[10], [](int* p) {delete[] p; });
sp.reset(); //使用我们提供的lambda释放数组
//shared_ptr没有定义下标运算符,并且不支持指针的算术运算
for (size_t i = 0; i != 10; i++) {
*(sp.get() + i) = i; //使用get来获取一个内置指针
}
}
//allocator类
void test06() {
allocator<string>alloc; //可以分配string的allocator对象
auto const p = alloc.allocate(10); //分配n个为初始化的string
auto q = p;
alloc.construct(q++);
alloc.construct(q++, 10, 'c');
cout << *p << endl;
cout << *q << endl;
while (q != p) {
alloc.destroy(--q); //释放我们真正构造的string
}
}
//文本查询程序
int main() {
system("pause");
return 0;
}
标签:string,int,动态内存,new,shared,unique,ptr 来源: https://www.cnblogs.com/best-you-articles-040612/p/16028922.html