C++中的auto_ptr智能指针的作用及使用方法详解
作者:2010120422 发布时间:2022-04-07 03:01:10
智能指针(auto_ptr) 这个名字听起来很酷是不是?其实auto_ptr 只是C++标准库提供的一个类模板,它与传统的new/delete控制内存相比有一定优势,但也有其局限。本文总结的8个问题足以涵盖auto_ptr的大部分内容。
auto_ptr是什么?
auto_ptr 是C++标准库提供的类模板,auto_ptr对象通过初始化指向由new创建的动态内存,它是这块内存的拥有者,一块内存不能同时被分给两个拥有者。当auto_ptr对象生命周期结束时,其析构函数会将auto_ptr对象拥有的动态内存自动释放。即使发生异常,通过异常的栈展开过程也能将动态内存释放。auto_ptr不支持new 数组。
该类型在头文件memory中,在程序的开通通过 #include<memory> 导入,接下来讲解该智能指针的作用和使用。
使用方法:
auto_ptr<type> ptr(new type()); 这是该指针的定义形式,其中 type 是指针指向的类型,ptr 是该指针的名称。
比如该type 是int,具体定义如下:
auto_ptr<int> ptr(new int(4));
比如该type 是map<int,vector<int> >,具体定义如下:
auto_ptr<map<int,vector<int> > > ptr(new map<int,vector<int> > ());
当然可以先定义,后赋值,如下所示:
auto_ptr<map<int,int> > ptr;
ptr = auto_ptr<map<int,int> >(new map<int,int> ());
作用1:保证一个对象在某个时间只能被一个该种类型的智能指针所指向,就是通常所说的对象所有权。
作用2:对指向的对象自动释放的作用,详情看如下代码。
代码片段一:
#include <iostream>
#include <string.h>
#include <memory>
#include <string>
#include <Windows.h>
#include <map>
#include <ctime>
#include <vector>
using namespace std;#define MAXN 20000000
class test_ptr
{
public:
map<int,int> *p;
test_ptr()
{
p = new map<int,int>();
for(int i = 0;i<MAXN;i++)
p->insert(make_pair(i,i));
}
};
int main(int argc,char *argv[])
{
for(int i = 0;i<100;i++)
{
Sleep(1000);
cout << i << endl; // 输出 创建次数
test_ptr * tmp = new test_ptr();
}
system("pause");
return 0;
}
在某些情况下,可能我们就会写出上面的代码来,通过运行会发现存在内存溢出。对于一些经验老道的程序员可能会作如下改写:
代码片段二:
#include <iostream>
#include <string.h>
#include <memory>
#include <string>
#include <Windows.h>
#include <map>
#include <ctime>
#include <vector>
using namespace std;
#define MAXN 20000000
class test_ptr
{
public:
map<int,int> *p;
test_ptr()
{
//p = auto_ptr<map<int,int> > (new map<int,int>());
p = new map<int,int>();
for(int i = 0;i<MAXN;i++)
p->insert(make_pair(i,i));
}
~test_ptr()
{
delete p;
}
};
int main(int argc,char *argv[])
{
for(int i = 0;i<100;i++)
{
Sleep(1000);
cout << i << endl;
test_ptr * tmp = new test_ptr();
}
system("pause");
return 0;
}
在test_ptr 类中的析构函数中添加内存释放代码,但是在main函数中,定义的局部指针,当局部指针失效时并不会自动调用析构函数,在这种情况下也会导致内存泄漏问题。当然,如果细心的程序员可以在 test_ptr * tmp = new test_ptr() 后面加上一句 delete tmp ,这样也能够释放内存,不会出现内存泄漏问题。但是在某些情况下,很容易漏写,为了解决此问题,auto_ptr 就能发挥作用了。
代码片段三:
#include <iostream>
#include <string.h>
#include <memory>
#include <string>
#include <Windows.h>
#include <map>
#include <ctime>
#include <vector>
using namespace std;
#define MAXN 20000000
class test_ptr
{
public:
map<int,int> *p;
test_ptr()
{
p = new map<int,int>();
for(int i = 0;i<MAXN;i++)
p->insert(make_pair(i,i));
}
~test_ptr()
{
delete p;
}
};
int main(int argc,char *argv[])
{
for(int i = 0;i<100;i++)
{
Sleep(1000);
cout << i << endl; //输出创建次数
auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr());
}
system("pause");
return 0;
}
在main函数中,创建test_ptr类型指针时,该指针是auto_ptr 类型的智能指针,当智能指针失效时,会自动调用该类的析构函数。所以这种写法可以不再显示调用delete 语句了。但是该智能指针也只是保证调用类的析构函数,如果析构函数并没有释放类中声明的变量,那该怎么办。
代码片段四:
#include <iostream>
#include <string.h>
#include <memory>
#include <string>
#include <Windows.h>
#include <map>
#include <ctime>
#include <vector>
using namespace std;
#define MAXN 20000000
class test_ptr
{
public:
//auto_ptr<map<int,int> > p;
map<int,int> *p;
test_ptr()
{
//p = auto_ptr<map<int,int> > (new map<int,int>());
p = new map<int,int>();
for(int i = 0;i<MAXN;i++)
p->insert(make_pair(i,i));
}
/*
~test_ptr()
{
delete p;
}
*/
};
int main(int argc,char *argv[])
{
for(int i = 0;i<100;i++)
{
Sleep(1000);
cout << i << endl; //输出创建次数
auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr());
}
system("pause");
return 0;
}
在这种情况下,还是会出现内存泄漏问题,为了解决该问题,对类中声明的指针也是需要声明为auto_ptr类型。
代码片段五:
#include <iostream>
#include <string.h>
#include <memory>
#include <string>
#include <Windows.h>
#include <map>
#include <ctime>
#include <vector>
using namespace std;
#define MAXN 20000000
class test_ptr
{
public:
auto_ptr<map<int,int> > p;
test_ptr()
{
p = auto_ptr<map<int,int> > (new map<int,int>());
for(int i = 0;i<MAXN;i++)
p->insert(make_pair(i,i));
}
};
int main(int argc,char *argv[])
{
for(int i = 0;i<100;i++)
{
Sleep(1000);
cout << i << endl; //输出创建次数
auto_ptr<test_ptr> tmp = auto_ptr<test_ptr> (new test_ptr());
}
system("pause");
return 0;
}
这样就不用显示定义类的析构函数,不用在外部显示调用delete函数,当然如果尽早调用delete函数也是可以的,尽早释放内存也比该指针失效再释放好一些,这些就是为了防止忘记调用。
通过如上分析:可以得出如下结论。
1 定义了智能指针,当智能指针失效时会自动调用类的析构函数。
2 在 类中定义的智能指针,不必在析构函数中显示的delete,当外部调用该类的析构函数时,会自动释放该智能指针指向的对象,释放内存。
3 如果类中定义的是智能指针,但是外部没有触发类中的析构函数调用,该智能指针指向的对象还是不能释放。
auto_ptr 智能指针的bug
auto_ptr 智能指针在c++ 11 标准中已经被抛弃,被抛弃的原因就是因为该bug。前面也提到过,一个对象只能被一个智能指针所引用,这样就会导致一个赋值问题。看如下代码
代码片段六:
#include <iostream>
#include <string.h>
#include <memory>
#include <set>
using namespace std;
#define MAXN 20000000
void pri(auto_ptr<set<int> > p)
{
set<int>::iterator ite = p->begin();
for(;ite!=p->end();ite++)
{
cout << *ite << endl;
}
}
int main(int argc,char *argv[])
{
auto_ptr<set<int> > ptr(new set<int> ());
for(int i = 0;i< 3;i++)
{
int a;
cin >> a;
ptr->insert(a);
}
pri(ptr);
pri(ptr);
system("pause");
return 0;
}
初看这代码没什么问题,不过运行程序会崩溃。这就是该智能指针最大的bug, 在程序32行 调用pri(ptr) ,程序到这并没什么问题,但是第二次调用pri(ptr) 时程序就会崩溃。原因就是前面讲过,一个对象智能被一个智能指针所指向,在第一次调用pri()函数时,为了保证这一原则,当把ptr指针传入pri函数时,程序内部就把ptr置为空,所以到第二次调用时,就会出现崩溃的情况。对于这种情况的解决之道就是使用shared_ptr 指针(该指针的原理是通过引用计数器来实现的)。
如果要使用shared_ptr 智能指针,需要安 * oost库,该库还包括许多其他功能。有兴趣的可以尝试以下,该类中的智能指针还是比较好用。也不存在很多其他bug。
以上所述是小编给大家介绍的C++中的auto_ptr智能指针实例详解网站的支持!
来源:http://www.cnblogs.com/ChenAlong/archive/2016/07/12/5662851.html
猜你喜欢
- 作为一个ORM框架,hibernate肯定也需要满足我们实现表与表之间进行关联的需要。hibernate在关联方法的实现很简单。下面我们先来
- 创建SpringBoot项目可以通过两种方式1、通过访问:https://start.spring.io/,SpringBoot的官方网站进
- ListView 的简单用法在布局中加入 ListView 控件还算简单,先为 ListView 指定一个 id,然后将宽度和高度都设置为
- 场景描述单例模式对于我们来说一点也不模式,是一个常见的名称,单例模式在程序中的实际效果就是:确保一个程序中只有一个实例,并提供一个全局访问点
- 在之前项目中有用到关于获取手机联系人的部分,闲置就想和大家分享一下,话不多说,上代码:java部分:package com.example.
- 例子:using System;using System.Collections.Generic;using System.Text;nam
- 本文实例讲述了Android编程实现二维码的生成与解析。分享给大家供大家参考,具体如下:直接上代码,代码上面有具体的解析,并且提供jar供下
- Spring的创建Spring的创建分为3个步骤:1、创建一个Maven项目2、添加Spring框架支持(spring-context,sp
- 一、显示信息对话框:使用“JOptionPane.showMessageDialog”显示:图标对话框类型语法显示错误类型对话框showMe
- android开发中为activity增加左右手势识别,如右滑关闭当前页面。/* * for左右手势 *&n
- 前言:自定义View可以分为两种方式:第一种通过继承ViewGroup,内部通过addView的方式将其他的View组合到一起。第二种则是通
- 一、MyBatis背景介绍MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码
- 在网上看到一个进度条效果图,非常美观,如下:进行效果分解:1.渐变色,看起来颜色变化并不复杂,使用LinearGradient应该可以实现。
- 1、概念首先我们理解一下,什么叫做完美数?问题描述:若一个自然数,它所有的真因子(即除了自身以外的约数)的和恰好等于它本身,这种数叫做完全数
- 前言最近做项目的时候遇到一个卡劵的效果,由于自己觉得用图片来做的话可以会出现适配效果不好,再加上自己自定义view方面的知识比较薄弱,所以想
- string filePath = @"E:\Randy0528\中文目录\JustTest.rar"; &n
- 一、线程池使用场景•单个任务处理时间短•将需处理的任务数量大二、使用Java线程池好处1、使用new Thread()创建线程的弊端:•每次
- 问题现象今天在做一个需求:将存入数据库中的数据读到后解析成list遍历分析数据格式:"[1677660600000, 167766
- 前言:各位小伙伴们,大家好,一日不见,如隔一日,今天我给大家分享一下大家在学习java过程当中遇到的一个问题,也是一道面试题,java中,O
- 介绍:unity界面开发,会用到很多导航的按钮,他们是公共的,单击其中一个按钮,显示对应的界面。unity中,UGUI自带Toggle组件,