C++11的新特性之shared_ptr和unique_ptr

C++11的新特性之shared_ptr和unique_ptr

本篇文章将继续介绍C++11的新特性-智能指针 shared_ptr和unique_ptr。关于所有C++11的重要的改变请参看,

C++11的重大改变

智能指正并不是C++11才引入的,早在C++98/03标准中已经有了auto_ptr。在C++11定义了新的智能指针来替代 std::auto_ptr.

std::auto_ptr在C++11已经不被推荐使用,当然你还可以用,不过在C++17版本中完全移除,也就是如果你编译的时候使用的是 -std=c++17,如果你使用std::auto_ptr,那么gcc会直接告诉你一个编译错误。

关于为什么auto_ptr被deprecated,stackoverflow上面有个帖子

Why is auto_ptr being deprecated?

shared_ptr和unique_ptr是标准模板库的模板类,所以使用的时候要加上它对应的命名空间-std,或者使用前声明

use namespace std;

或者

std::shared_ptr   std::unique_ptr

 

基本用法

例如,定义保存int指针的智能指针,

std::shared_ptr<int> myintptr(new int);
std::unique_ptr<int> myintptr(new int);
class Base{};
class Derived : public Base {};
std::shared_ptr<Base> p = std::make_shared<Derived>();

这里说一下std::make_shared是c++17定义的方法。

那么什么情况下用std::shared_ptr什么情况下使用std::unique_ptr呢

它们的共同之处是开发人员不在需要关心指针所指向的内存的释放问题,当这块内存不在被引用时,那么会被自动释放。区别是,指向同一内存的某一类型的指针的数量的多少,std::unique_ptr只允许一个,而std::shared_ptr允许多个。

std::unique_ptr 最多允许一个,当这个智能指针被销毁时,对应的内存会被自动释放。如果你试图去拷贝一个std::unique_ptr,那么编译器会报错,例如下面的代码就会报错
std::unique_ptr<Base> p(new Base);  // 没有问题
std::unique_ptr<Base> p1 = p;  // 这里会有编译错误,不能拷贝std::unique_ptr

但是std::unique_ptr支持move语法,所以你可以这样

std::unique_ptr<Base> p(new Base); // 没有问题
std::unique_ptr<Base> p1 = std::move(p); // 没有问题

对于std::shared_ptr,上面的拷贝的那个例子就没有任何问题,

std::shared_ptr<Base> p(new Base); // 没有问题
std::shared_ptr<Base> p1 = p; // 没有问题

类的智能指针变量

如果不能做下面的操作,那么怎么定义一个类的智能指正类成员变量?

std::unique_ptr<Base> p1 = p;

这个就需要用到智能指针的reset()方法

std::unique_ptr::reset

下面是一个例子:

#include <memory>
#include “ClassB.h”

class ClassA
{
public:
ClassA() = default;
virtual ~ClassA() = default;
bool create( void );

ClassA( const ClassA& ) = delete;
ClassA& operate=( const ClassA& ) = delete;

private:
std::unique_ptr m_anotherClassPtr;
}

bool ClassA::create( void )
{
m_anotherClassPtr.reset( new ClassB );
return true;
}

 

智能指针是否为空

智能指针定义操作符 bool

std::unique_ptr::operator bool

来判断一个指针是否不为空,是不为空,所以如果返回值是true,那么就是该智能指针已经有值,相当于

get()!=nullptr

关于get()后面又解释。

下面是一个例子,

#include <iostream>
#include <memory>


int main () {
  std::unique_ptr<int> foo;
  std::unique_ptr<int> bar (new int(12));

  if (foo) std::cout << "foo points to " << *foo << '\n';
  else std::cout << "foo is empty\n";

  if (bar) std::cout << "bar points to " << *bar << '\n';
  else std::cout << "bar is empty\n";

  return 0;
}

获取智能指针所管理的内部指针

C++11定义了

std::unique_ptr::get

来获取智能指针所管理的内部指针

下面是个例子,

// unique_ptr::get vs unique_ptr::release
#include <iostream>
#include <memory>

int main () {
                                           // foo   bar    p
                                           // ---   ---   ---
  std::unique_ptr<int> foo;                // null
  std::unique_ptr<int> bar;                // null  null
  int* p = nullptr;                        // null  null  null

  foo = std::unique_ptr<int>(new int(10)); // (10)  null  null
  bar = std::move(foo);                    // null  (10)  null
  p = bar.get();                           // null  (10)  (10)
  *p = 20;                                 // null  (20)  (20)
  p = nullptr;                             // null  (20)  null

  foo = std::unique_ptr<int>(new int(30)); // (30)  (20)  null
  p = foo.release();                       // null  (20)  (30)
  *p = 40;                                 // null  (20)  (40)

  std::cout << "foo: ";
  if (foo) std::cout << *foo << '\n'; else std::cout << "(null)\n";

  std::cout << "bar: ";
  if (bar) std::cout << *bar << '\n'; else std::cout << "(null)\n";

  std::cout << "p: ";
  if (p) std::cout << *p << '\n'; else std::cout << "(null)\n";
  std::cout << '\n';

  delete p;   // the program is now responsible of deleting the object pointed to by p
              // bar deletes its managed object automatically

  return 0;
}

 

基类的智能指针转换为子类的智能指针

c++的多态的实现是通过指针或者引用实现。

例如下面的例子

“`C++
class CA
{
};

class CB : public CA
{

};

class CC : public CA
{

};

class CClient
{
private:
shared_ptr<CA> m_pCAInstance;
}

CClient::CClient()
{
m_pCAInstance = std::make_shared<CB>();
}
““
如果m_pCAInstance想调用CB的一个public方法,那么我们就要m_pCAInstance转换成CA,这个需要用dynamic_pointer_cast

std::shared_ptr pCB = std::dynamic_pointer_cast( m_pCAInstance );

先简单写到这里,等有时间了,再进行补充。

 

参考

http://en.cppreference.com/w/cpp/memory/shared_ptr

http://en.cppreference.com/w/cpp/memory/unique_ptr

 

版权所有,禁止转载. 如需转载,请先征得博主的同意,并且表明文章出处,否则
按侵权处理.

    分享到:
This entry was posted in C/C++ and tagged . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*