【足迹C++primer】39、动态内存与智能指针(2)

来源:互联网 发布:大数据笔试题目 编辑:程序博客网 时间:2024/06/07 08:49
动态内存与智能指针(2)

直接管理内存

void fun1(){    //此new表达式在自由空间构造一个int型对象,并返回指向该对象的指针    int *pi1=new int;     //pi指向一个动态分配、未初始化的无名对象    string *ps3=new string;      //初始化为空string    int *pi2=new int;        //pi指向一个未初始化的int    int *pi3=new int(1024);      //pi指向的对象的值为1024    string *ps4=new string(10, '9'); //*ps为“999999999”    //vector有10个元素,值依次从0到9    vector<int> *pv=new vector<int>{0,1,2,3,4,5,6,7,8,9};    string *ps1=new string;     //默认初始化为空string    string *ps=new string();    //值初始化为空string    int *pi4=new int;           //默认初始化;*pi1的值未定义    int *pi5=new int();         //值初始化为0;*pi2为0}

由于编译器要用初始化器的类型来推断要分配的类型,只有当括号中仅有单一初始化器
时才可以使用auto

void fun2(){    int obj;    auto p1=new auto(obj);      //p指向一个与obj类型相同的对象                                //该对象用obj进行初始化//    auto p2=new auto{a,b,c};       //错误:括号中只能有单个初始化器}

动态分配的const对象

void fun3(){    //用new分配const对象是合法的:    //分配并初始化一个const int    const int *pci=new const int(1024);    //分配并默认初始化一个const的空string    const string *pcs=new const string;}

对于一个定义了默认构造函数的类类型,其const动态对象可以隐式初始化,
而其他类型的对象就必须显示初始化,由于分配的对象是const的,new返回
的指针是一个指向const的指针

内存耗尽

一旦一个程序用光了它所有可用的内存,new表达式就会失败。默认情况下,如果new
不能分配所要求的内存空间,他就会抛出一个类型为bad_alloc的异常,我们可以使用
new的方式来阻止它抛出异常
void fun4(){//如果分配失败,new返回一个空指针    int *p1=new int;    //如果分配失败,new抛出std::bad_alloc    int *p2=new (nothrow) int;      //如果分配失败,new返回一个空指针//我们称这种形式的new为定位new,bad_alloc和nothrow都保存在头文件new中}

释放动态内存

void fun5(){    int *p=nullptr;    delete p;       //p必须指向一个动态分配的对象或是一个空指针}

指针值和delete

释放一块并非new分配内存,或者将相同的指针值释放多次,其行为是未定义的
void fun6(){    int i, *pi1=&i, *pi2=nullptr;    double *pd=new double(33), *pd2=pd;    delete i;   //错误i不是一个指针    delete pi1; //未定义    delete pd;  //正确    delete pd2; //未定义:pd2指向的内存已经被释放了    delete pi2; //正确:释放一个空指针总是没有错误的//虽然一个const对象的值不能被改变,但它本身是可以被销毁的    const int *pci=new const int(1024);    delete pci; //正确:释放一个const对象}

动态对象的生存期直到被释放时为止

对于一个由内置指针管理的动态对象,直到被显式释放之前它都是存在的

typedef int T;struct Foo {  // members are public by defaultFoo(T t): val(t) { }T val;};//factory返回一个指针,指向一个动态分配对象Foo* factory(T arg){    //视情况处理arg    return new Foo(arg);        //调用者负责释放此内存}void use_factory1(T arg){    Foo *p=factory(arg);    //使用p但不delete它}   //p离开它的作用域,但是他所指向的内存没有释放!//由内置指针管理的动态内存再被显式释放前一直都会存在。void use_factory2(T arg){    Foo *p=factory(arg);    //使用p而且delete它    delete p;}

当有两个指针指向相同的动态分配对象的时候,可能发生这种错误
如果对其中一个指针做了delete操作,对象的内存就返回给自由空间了
如果我们delete第二个指针,自由空间就可能被破坏。
坚持使用智能指针就能避免这些问题

delete后重置指针值

在delete之后指针就变成了我们所说的悬空指针,即指向一块曾经保存数据对象但现在
已经无效的内存指针
在指针将要离开其作用域之前释放掉它关联的内存
如果我们需要保留指针,可以再delete之后将nullptr赋予指针
这样就清楚地指出指针不指向任何对象

。。。这只是提供了有限的保护

void fun7(){    int *p(new int(42));    //p指向动态内存    auto q=p;               //p和q指向相同的内存    delete p;               //p和q均变成无效    p=nullptr;              //指出p不再绑定到任何对象}

课后习题来一发!!!

/**
*   编写函数,返回一个动态分配的int的vector.将vector传递给另一个函数,
*   这个函数读取标准输入,将读入的值保存在vector元素中。再将vector
*   传递给另一个函数,打印读入值。记得在恰当地时候delete vector
*/

vector<int>* getVector(){    vector<int> *pv=new vector<int>{1,2,3,4,5,6,7,8,9};    return pv;}void fun8(vector<int> *pv){    int i;    //读入元素    while(cin>>i)    {        pv->push_back(i);    }}void show(vector<int> *pv){    for(vector<int>::const_iterator it=pv->cbegin() ; it != pv->cend() ; ++it)    {        cout<<*it<<"\t";    }    delete pv;}

使用shared_ptr写

//使用shared_ptr书写shared_ptr<vector<int>> get_vector(){    return shared_ptr<vector<int>>(new vector<int>{1,2,3,4,5,6,7,8,9});}void addVector(shared_ptr<vector<int>> pv){    int i;  //要添加的元素    while(cin>>i)    {        vector<int> *v=pv.get();        v->push_back(i);    }}void showShared_ptr(shared_ptr<vector<int>> pv){    //取出shared_ptr里面的对象指针    vector<int> *v=pv.get();    //输出vector里面的数据    for(vector<int>::const_iterator it=v->cbegin() ; it != v->cend() ; ++it)    {        cout<<*it<<"\t";    }}

shared_ptr和new结合使用

void fun9(){    shared_ptr<double> p1;   //shared_ptr可以指向一个double    shared_ptr<int> p2(new int(42));        //p2指向一个值为42的int//    shared_ptr<int> p1=new int(1024);       //错误:必须使用直接初始化形式    shared_ptr<int> p21(new int(1024));      //正确:使用直接初始化形式}shared_ptr<int> clone(int p){    //正确:显示使用int*创建shared_ptr<int>    return shared_ptr<int>(new int(p));}

全部代码输出!

/*** 功能:动态内存与智能指针* 时间:2014年7月7日16:41:57* 作者:cutter_point*/#include<iostream>#include<string>#include<vector>#include<new>#include<memory>using namespace std;void fun1(){    //此new表达式在自由空间构造一个int型对象,并返回指向该对象的指针    int *pi1=new int;     //pi指向一个动态分配、未初始化的无名对象    string *ps3=new string;      //初始化为空string    int *pi2=new int;        //pi指向一个未初始化的int    int *pi3=new int(1024);      //pi指向的对象的值为1024    string *ps4=new string(10, '9'); //*ps为“999999999”    //vector有10个元素,值依次从0到9    vector<int> *pv=new vector<int>{0,1,2,3,4,5,6,7,8,9};    string *ps1=new string;     //默认初始化为空string    string *ps=new string();    //值初始化为空string    int *pi4=new int;           //默认初始化;*pi1的值未定义    int *pi5=new int();         //值初始化为0;*pi2为0}//由于编译器要用初始化器的类型来推断要分配的类型,只有当括号中仅有单一初始化器//时才可以使用autovoid fun2(){    int obj;    auto p1=new auto(obj);      //p指向一个与obj类型相同的对象                                //该对象用obj进行初始化//    auto p2=new auto{a,b,c};       //错误:括号中只能有单个初始化器}//动态分配的const对象void fun3(){    //用new分配const对象是合法的:    //分配并初始化一个const int    const int *pci=new const int(1024);    //分配并默认初始化一个const的空string    const string *pcs=new const string;    //对于一个定义了默认构造函数的类类型,其const动态对象可以隐式初始化,    //而其他类型的对象就必须显示初始化,由于分配的对象是const的,new返回    //的指针是一个指向const的指针}//内存耗尽void fun4(){//一旦一个程序用光了它所有可用的内存,new表达式就会失败。默认情况下,如果new//不能分配所要求的内存空间,他就会抛出一个类型为bad_alloc的异常,我们可以使用//new的方式来阻止它抛出异常//如果分配失败,new返回一个空指针    int *p1=new int;    //如果分配失败,new抛出std::bad_alloc    int *p2=new (nothrow) int;      //如果分配失败,new返回一个空指针//我们称这种形式的new为定位new,bad_alloc和nothrow都保存在头文件new中}//释放动态内存void fun5(){    int *p=nullptr;    delete p;       //p必须指向一个动态分配的对象或是一个空指针}//指针值和delete//释放一块并非new分配内存,或者将相同的指针值释放多次,其行为是未定义的void fun6(){    int i, *pi1=&i, *pi2=nullptr;    double *pd=new double(33), *pd2=pd;//    delete i;   //错误i不是一个指针    delete pi1; //未定义    delete pd;  //正确    delete pd2; //未定义:pd2指向的内存已经被释放了    delete pi2; //正确:释放一个空指针总是没有错误的//虽然一个const对象的值不能被改变,但它本身是可以被销毁的    const int *pci=new const int(1024);    delete pci; //正确:释放一个const对象}//动态对象的生存期直到被释放时为止//对于一个由内置指针管理的动态对象,直到被显式释放之前它都是存在的typedef int T;struct Foo {  // members are public by defaultFoo(T t): val(t) { }T val;};//factory返回一个指针,指向一个动态分配对象Foo* factory(T arg){    //视情况处理arg    return new Foo(arg);        //调用者负责释放此内存}void use_factory1(T arg){    Foo *p=factory(arg);    //使用p但不delete它}   //p离开它的作用域,但是他所指向的内存没有释放!//由内置指针管理的动态内存再被显式释放前一直都会存在。void use_factory2(T arg){    Foo *p=factory(arg);    //使用p而且delete它    delete p;}/**当有两个指针指向相同的动态分配对象的时候,可能发生这种错误*  如果对其中一个指针做了delete操作,对象的内存就返回给自由空间了*  如果我们delete第二个指针,自由空间就可能被破坏。*  坚持使用智能指针就能避免这些问题*///delete后重置指针值/***   在delete之后指针就变成了我们所说的悬空指针,即指向一块曾经保存数据对象但现在*   已经无效的内存指针*   在指针将要离开其作用域之前释放掉它关联的内存*   如果我们需要保留指针,可以再delete之后将nullptr赋予指针*   这样就清楚地指出指针不指向任何对象*///。。。这只是提供了有限的保护void fun7(){    int *p(new int(42));    //p指向动态内存    auto q=p;               //p和q指向相同的内存    delete p;               //p和q均变成无效    p=nullptr;              //指出p不再绑定到任何对象}/***   编写函数,返回一个动态分配的int的vector.将vector传递给另一个函数,*   这个函数读取标准输入,将读入的值保存在vector元素中。再将vector*   传递给另一个函数,打印读入值。记得在恰当地时候delete vector*/vector<int>* getVector(){    vector<int> *pv=new vector<int>{1,2,3,4,5,6,7,8,9};    return pv;}void fun8(vector<int> *pv){    int i;    //读入元素    while(cin>>i)    {        pv->push_back(i);    }}void show(vector<int> *pv){    for(vector<int>::const_iterator it=pv->cbegin() ; it != pv->cend() ; ++it)    {        cout<<*it<<"\t";    }    delete pv;}//使用shared_ptr书写shared_ptr<vector<int>> get_vector(){    return shared_ptr<vector<int>>(new vector<int>{1,2,3,4,5,6,7,8,9});}void addVector(shared_ptr<vector<int>> pv){    int i;  //要添加的元素    while(cin>>i)    {        vector<int> *v=pv.get();        v->push_back(i);    }}void showShared_ptr(shared_ptr<vector<int>> pv){    //取出shared_ptr里面的对象指针    vector<int> *v=pv.get();    //输出vector里面的数据    for(vector<int>::const_iterator it=v->cbegin() ; it != v->cend() ; ++it)    {        cout<<*it<<"\t";    }}//shared_ptr和new结合使用void fun9(){    shared_ptr<double> p1;   //shared_ptr可以指向一个double    shared_ptr<int> p2(new int(42));        //p2指向一个值为42的int//    shared_ptr<int> p1=new int(1024);       //错误:必须使用直接初始化形式    shared_ptr<int> p21(new int(1024));      //正确:使用直接初始化形式}shared_ptr<int> clone(int p){    //正确:显示使用int*创建shared_ptr<int>    return shared_ptr<int>(new int(p));}int main(){/*    vector<int> *pv=getVector();    fun8(pv);    show(pv);*/    shared_ptr<vector<int>> pv=get_vector();    addVector(pv);    showShared_ptr(pv);    return 0;}

PS:看这章好累啊,感觉比以前麻烦多了,但是还是要保持好心态,好好看,好好学,不知道这样学下去什么时候才是个尽头啊,以后怎么找工作啊哭哭哭哭哭


0 0
原创粉丝点击