C++中的动态内存与智能指针

在C++中,我们通过new(在动态内存中为对象分配空间并初始化对象)和delete(销毁该对象,并释放内存)直接分配和释放动态内存。

如下代码:

有些人有这样的疑问,指针一定要new吗?其实指针和new没有什么关系。这里的new在动态内存里为对象分配了内存空间,并返回了一个指向该对象的指针。new是申请堆空间,不是在栈上分配内存,指针只要指向有效的内存空间就可以。比如:

new直接初始化对

象:

new分配const对象必须进行初始化,并且返回的是一个指向const对象的指针:

当然new申请内存分配的时候也不是都会成功的,一旦一个程序用光了他的所有可用内存(虽然这种情况一般很少发生),new表达式就会失败。这时候会抛出bad_alloc异常。所以我们需要通过delete来释放占用的内存。在这里注意delete并不是要删除指针,而是释放指针所指的内存。

使用new和delete来管理动态内存常出的一些错误:

1.忘记delete,即导致了“内存泄漏”,

2.野指针。在对象已经被释放掉之后,(这里注意,此时的指针成为了悬垂指针,即指向曾经存在的对象,但该对象已经不再存在。结果未定义,而且难以检测。)这时候我们再次使用,会产生使用非法内存的指针。

不过如果我们需要保留指针,可以在delete以后将nullptr赋予指针,这样指针就不指向任何对象了,如下代码:

 

题外话:在测试这个问题的时候,我输出了下q的值发现还是42,并且没有报错,后来在delete p之后,我又给*p = 19;这个时候 p ,q的值在输出的时候都是19,也没有报错。这个代码其实根本就是错误的了,因为p,q已经没有有效的内存空间了。这里是释放了内存,但指针的值不变,指向的内存不会清0,指向的这片内存区域是待分配的,如果没有被其他数据覆盖的话,你就能幸运得输出这主要原因是你分配的内存小,没有继续分配,被占用的概率小所致。我用的xcode,换到VS下就正常报错了,是因为VS为了从编译器的角度上解决缓冲区溢出等问题,加上的这种功能,C++标准里面没有这么要求,所有xcode和gcc是不会检查的。所以在这里 建议大家写纯C++代码的时候用vs。

3.重复delete,就会使自由空间遭到破坏如:

虽然显示的管理内存在性能上有一定的优势,但是随着多线程程序的出现和广泛使用,内存管理不佳的的情况变得更严重。所以C++标准库中的智能指针很好的解决了这些问题。

auto_ptr以对象的方式管理堆分配的内存,并在适当的时间(比如析构),释放内存。我们只需要将new操作返回的指针作为auto_ptr的初始值,而不需要调用delete:

但是auto_ptr在拷贝时会返回一个左值并且不能调用delete[];所以在C++11中改用shared_ptr(允许多个指针指向一个对象),unique_ptr(“独占”所指向的对象)还有weak_ptr它是一种不控制所指对象生存期的智能指针,指向shared_ptr所管理的对像,在memory头文件中。

如下代码:

当然我们也可以shared_ptr和new来结合使用,但是必须使用直接初始化的形式来初始化一个智能指针,

但是最好不要混合使用普通指针和智能指针,最安全的分配和使用动态内存的方法是调用make_shared的标准库函数。在使用它的时候,必须指定想要创建的对象类型。

如果我们不传递任何参数,对象会进行值初始化

shared_ptr 实现了引用计数型的智能指针,当进行拷贝的时候,计数器都会递增。而对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(减1,如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数(加1),如下代码:

此时r的引用技术为0,r原指对象被自动释放。q的引用计数增加。

weak_ptr的使用和析构都不会改变shared_ptr的引用计数。weak_ptr可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象, 从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr.如下:

当我们定义一个unique_ptr的时候,需要将其绑定到一个new返回的指针。

只能有一个uniqu_ptr指向对象,也就是说它不能被拷贝,也不支持赋值。但是我们可以通过move来移动

8 收藏 19 评论

关于作者:christian

I am an onion and one cries while peeling it (新浪微博:@Onion_christian李阳) 个人主页 · 我的文章

相关文章

可能感兴趣的话题



直接登录
最新评论
  • neo   2014/01/20

    作者你确认: string ps = new string("christian"); const int p = new const int(1024);能编译得过?

    还得请教:
    int i;
    int *p = &i;
    p->i; // 这个是啥用法???

  • geansea   2014/01/21

    2.野指针。在对象已经被释放掉之后,指针会置为空。这时候我们再次使用,会产生使用非法内存的指针。
    “指针会置为空……”->如果指针没有置空,当再次使用时,其指向的内存是非法的,可能会遇到或造成不可预计的状态。

    不过如果我们需要保留指针,可以在delete以后将nullptr赋予指针,这样指针就不指向任何对象了,如下代码:
    “不过如果我们需要保留指针……”->不过如果我们需要保留指针变量,可以在delete以后将其赋值为nullptr,这样指针就不指向任何对象了(但在使用之前需要判断是否为null,否则会产生空指针错误),如下代码:

    俺自己理解改的,语言未必准确,望参考。

    • geansea   2014/01/21

      俺->按,汗……

    • 改过了,当delete之后,指针并没有被置为空指针,而是悬垂指针。需要=null才会被置空。
      至于p = nullptr;之后p已经是空指针了所以不需要检测了

    • geansea   2014/01/21

      第一个里面我写的是“如果指针没有置空”。

      第二个里面我是想提醒下空指针的问题,野指针和空指针是最常遇到的指针类错误,double free反而不太容易遇到,释放后立即置空一般都会作为最基础的开发规范。

      空指针的检查在c++里少不了的吧,即使智能指针在用之前也要看下get()到的是不是空,除非有默认的空对象。

  • 我知道你~有关注你微博。c++11 我知道呢,我可以去你们公司不?

  • "此时r的引用技术为0,r原指对象被自动释放。q的引用计数增加。"
    是不是应该是r原指对象的引用计数为0,r原指对象被自动释放。q所指对象的引用计数增加。

跳到底部
返回顶部