0
点赞
收藏
分享

微信扫一扫

C\C++_指针_智能指针模板类

Yaphets_巍 2022-02-03 阅读 26
c++c语言

模板种类

智能指针模板类支持情况使用场景
auto_ptrC++98提供的,C++11已摒弃,但如果编译器不支持其它两种C++11提供的,则只能使用auto_ptr
unique_ptrC++11提供 (如果编译器没提供,可使用Boost库的scoped_ptr)不需要多个指向同一对象的指针
shared_ptrC++11 提供(如果编译器没提供,可使用Boost库的shared_ptr)多个指针指向同一个对象,支持复制和赋值操作

智能指针使用示例

#include <memory>
#include <string>
#include <iostream>

class CReport
{
private:
    std::string m_str;

public:
    CReport(const std::string &str)
        :m_str(str)
    {
       std::cout << "Object created!!!\n"; 
    }
    ~CReport()
    {
        std::cout << "Object deleted!!!\n";
    }
    void Show() const
    {
        std::cout << m_str << "\n";
    }
};

void Test01()
{
    //! 都是模板类,本质就是模板类中维护一个T*指针,通过析构函数来delete T*指针
    std::auto_ptr<CReport> pa(new CReport("using auto_ptr"));   
    pa->Show();     

     std::shared_ptr<CReport> ps(new CReport("using shared_ptr"));   
    ps->Show();     

    std::unique_ptr<CReport> pu(new CReport("using unique_ptr"));   
    pu->Show();     
}

有关智能指针的注意事项

  1. 三种智能指针都应避免
std::string str ("hello");
shared_ptr<std::string> pstr(&str);	//< 不允许
// 因为pstr过期时, 析构会delete对象内部维护的std::string指针,而这里str是栈上的内存,不是堆空间的,这里将把delete运算符用于非堆内存,非法操作
  1. 三种智能指针对赋值语句的策略
    请添加图片描述
  • auto_ptr
 	std::auto_ptr<std::string> pa(new std::string("hello world"));
    std::auto_ptr<std::string> pa1;
    pa1 = pa;       				//< 赋值的时候,移交了所有权给pa1
    std::cout <<* pa.get();         //< 异常,因为pa交出了所有权,所以pa维护的std::string指针为空,导致以打印的时候会出错
    std:: cout << *pa1.get();       //< 正常
  • shared_ptr
   	std::shared_ptr<std::string> pa(new std::string("hello world"));    //< 引用计数+1
    std::shared_ptr<std::string> pa1;   //< 引用计数+1
    pa1 = pa;           				//< 内部维护的std::string指针指向同一个堆空间
    std::cout <<*pa.get() << std::endl;          //< 正常,没有所有权的概念,采用引用计数的方式,
                                                 //< 只有引用计数降为0的时候,析构才delete所维护的std::string指针
    std:: cout << *pa1.get();                    //< 正常
  • unique_ptr
 	//! unique_ptr也是使用所有权模型,与auto_ptr一样,但unique_ptr赋值会在编译阶段就报错
    std::unique_ptr<std::string> pa(new std::string("hello world"));    
    std::unique_ptr<std::string> pa1; 
    pa1 = pa;           //< 这里在编译阶段就报错
    std::cout <<*pa.get() << std::endl;                            
    std:: cout << *pa1.get();       

unique_ptr优于auto_ptr

  • 编译器阶段错误比潜在的程序崩溃更安全
    std::unique_ptr<std::string> pa(new std::string("hello world"));    
    std::unique_ptr<std::string> pa1; 
    pa1 = pa;           //< 这里在编译阶段就报错,但如果使用auto_ptr,则编译不会报错,
    					//<	使用pa内部维护的std::string指针时才会出错
  • 允许赋值的情况
    程序试图将一个unique_ptr赋给另一个时,如果源unique_ptr是个临时右值,编译器允许这样做;但如果源unique_ptr将存在一段时间,编译器将禁止这样做。如下代码示例:
 std::unique_ptr<std::string> pu(new std::string("hello world"));
 std::unique_ptr<std::string> pu1;
 // pu1 = pu;             //< 编译器禁止这么做,因为pu长期存在,可能会存在使pu中的std::string对象的情况

 std::unique_ptr<std::string> pu3;
 pu3 = std::unique_ptr<std::string>(new std::string("hello world")); //< 允许,因为右边生成的临时对象,再把std::string对象的所有权移交给pu3后,会很快被销毁,没有机会使用它来访问无效的数据

//! 函数的返回值,也是临时右值,可以这么使用,当把临时右值赋值给接收者变量std::unique_ptr后,
//! 转移了所有权,临时右值会被销毁
std::unique_ptr<std::string> Get()
{
	std::unique_ptr<std::string> pu(new std::string("hello"));
	return pu;
}

  • 可用于数组的变体
    请添加图片描述
    使用new分配内存——可以使用auto_ptr、shared_ptr和unique_ptr
    使用new[]分配内存——可以使用unique_ptr

unique_ptr转为shared_ptr

模板shared_ptr包含一个显示构造函数,可将右值unique_ptr转换为shared_ptr,share_ptr将接管原来归unique_ptr所有的对象

std::unique_ptr<int> GetUni(int n)
{
    return std::unique_ptr<int>(new int(n));
}

int main()
{
    std::unique_ptr<int> pu(GetUni(3));     //< 正确,pu构造函数内为临时的unique_ptr<int>对象
    std::shared_ptr<int> ps(pu);                  //< 报错,编译器不允许右值为非临时变量
    std::shared_ptr<int> puts(GetUni(3));  //<  正确,将临时的unique_ptr<int>对象转为shared_ptr<int>对象
    
	return 0;
}

参考书籍

C++ Primer Plus(第6版)——16.2 智能指针模板类

举报

相关推荐

【C++】智能指针

C++——智能指针

C++ 智能指针

C++智能指针

C++-详解智能指针

C++ 11 智能指针

0 条评论