为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer)。在现代 c + + 编程中,标准库包含 智能指针,这些指针用于帮助确保程序不会出现内存和资源泄漏,并具有异常安全。C++11提供了三种智能指针:std::shared_ptr, std::unique_ptr, std::weak_ptr
,使用时需添加头文件#include< memory >。
shared_ptr
类型是 C++ 标准库中的一个智能指针,是为多个所有者可能必须管理对象在内存中的生命周期的方案设计的。shared_ptr
使用引用计数,每一个 shared_ptr
的拷贝都指向相同的内存。每引用它一次,内部的引用计数加1,每析构一次,内部的引用计数减1,减为0时,删除所指向的堆内存。shared_ptr内部的引用计数是安全的,但是对象的读取需要加锁。
智能指针的特殊之处在于帮助编程开发人员管理内存,确保程序不会出现内存和资源泄漏,并具有异常安全。
#include <iostream>
#include <memory>
using namespace std;
class Data
{
public:
Data() {
cout << "构造" << endl;
}
~Data() {
cout << "析构" << endl;
}
};
int main()
{
cout<<"智能指针:"<<endl;
{
std::shared_ptr<Data> Ptr(new Data); //智能指针出了作用域就会被释放,引用计数减一
}
cout<<"普通指针:"<<endl;
Data* ptr = new Data;
delete ptr;
return 0;
}
ubuntu@VM-16-5-ubuntu:~$ g++ -std=c++11 -o test test.cpp
ubuntu@VM-16-5-ubuntu:~$ ./test
智能指针
构造
析构
普通指针
构造
析构
从输出可以看出智能指针不需要手动释放,出了作用域之后就自动释放了,也就是说智能指针生命周期结束之后就会自动释放内存。而普通指针需要手动释放,不然会造成内存泄露。
主要描述智能指针 shared_ptr
的创建,重置和管理对象的释放
#include <iostream>
#include <memory>
using namespace std;
class Data
{
public:
Data(int id):m_id(id) {
cout << m_id <<":构造" << endl;
}
~Data() {
cout << m_id << "析构" << endl;
}
int m_id;
};
typedef std::shared_ptr<Data> DataPtr;
int main()
{
{
DataPtr dataPtr1 (new Data(1)); //new一个 shared_ptr 对象
DataPtr dataPtr2 = std::make_shared<Data>(2);//构造一个 shared_ptr对象
dataPtr1.reset(); //重置智能指针,释放其关联的指针内存
// 首先new Data对象,然后智能指针引用计数减1,引用计数为0,故析构 Data(1),智能指针载指向 Data(3)
dataPtr2.reset(new Data(3));
cout<<"即将离开作用域"<<endl;
}
return 0;
}
ubuntu@VM-16-5-ubuntu:~$ ./test
1:构造
2:构造
1析构
3:构造
2析构
即将离开作用域
3析构
main over
主要描述智能指针的共享管理,共享之后引用计数加一, shared_ptr
的创建,获取管理的对象
#include <iostream>
#include <memory>
using namespace std;
class Data
{
public:
Data(int id):m_id(id) {
cout << m_id <<":构造" << endl;
}
~Data() {
cout << m_id << "析构" << endl;
}
int m_id;
};
typedef std::shared_ptr<Data> DataPtr;
int main()
{
{
DataPtr dataPtr1(new Data(1)); //new一个 shared_ptr 对象
cout << "ptr1 conut:" << dataPtr1.use_count() << endl; //获取 dataPtr1 的引用计数
{
DataPtr dataPtr2 = dataPtr1; // dataPtr2 和 dataPtr1 共享管理一个对象 dataPtr1 引用计数加一
cout << "ptr1 conut:" << dataPtr1.use_count() << endl;
cout << "ptr2 conut:" << dataPtr2.use_count() << endl;
Data* pData = dataPtr2.get(); // 获取 shared_ptr 管理的对象,引用计数不变
cout << "Data id:"<<pData->m_id << endl;
cout<<"即将离开作用域"<<endl;
}
cout << "ptr1 conut:" << dataPtr1.use_count() << endl;
}
cout<<"main over"<<endl;
return 0;
}
ubuntu@VM-16-5-ubuntu:~$ g++ -std=c++11 -o test test.cpp
ubuntu@VM-16-5-ubuntu:~$ ./test
1:构造
ptr1 conut:1
ptr1 conut:2
ptr2 conut:2
Data id:1
即将离开作用域
ptr1 conut:1
1析构
main over
在多肽里面,基类对象指向子类对象,对基类对象的delete操作不会执行子类析构,从而造成内存泄漏。那么由指针管理的基类对象(指向子类对象)的释放操作释放的是基类还是子类对象?
#include <vector>
#include <memory>
#include <iostream>
using namespace std;
class Father
{
public:
Father(std::string name) {}
~Father() {cout<<"父类析构"<<endl;} //通过虚函数也可以解决这个内存泄漏问题
std::string m_name;
};
typedef std::shared_ptr< Father > FatherPtr;
class Son:public Father
{
public:
Son(std::string name) :Father(name) { m_name = name; }
~Son() { cout<<"子类析构"<<endl; }
};
typedef std::shared_ptr<Father> FatherPtr;
int main()
{
{
FatherPtr test(new Son("deroy"));
}
cout<<"-------------------------"<<endl;
Father* Ptr = new Son("test");
delete Ptr;
return 0;
}
ubuntu@VM-16-5-ubuntu:~$ g++ -std=c++11 -o test test.cpp
ubuntu@VM-16-5-ubuntu:~$ ./test
子类析构
父类析构
-------------------------
父类析构
从输出上来看,智能指针 shared_ptr
管理的基类对象(指向子类对象)的释放操作释放的是子类对象,不会造成内存泄露
引用计数为0之后我不想智能指针来帮我释放内存,我想自己释放内存可以吗?智能指针结合匿名函数综合应用。
#include <iostream>
#include <string>
#include <memory>
using namespace std;
class Person
{
public:
Person(string name)
{
m_name = name;
}
~Person(){
std::cout << "父类析构:" << m_name << std::endl;
}
virtual void fun() { cout << m_name << ":我该干点什么事情好呢?" << endl; };
public:
string m_name;
};
typedef std::shared_ptr<Person> PersonPtr;
class Student : public Person
{
public:
Student(string name) : Person(name)
{
std::cout << "new:" << m_name << std::endl;
}
~Student(){
std::cout << "子类析构:" << m_name << std::endl;
}
virtual void fun() { cout << m_name << ":我该干点什么事情好呢?" << endl; };
};
PersonPtr createPerson( string name )
{
#if 1
PersonPtr ptr = PersonPtr(new Student(name), [](void *val) {
Student *p = (Student *)(val);
if (p)
{
cout<<"use_count=0,call lambda release function"<<endl;
p->fun();
delete p;
}
});
#else
PersonPtr ptr = PersonPtr(new Student(name));
#endif
return ptr;
}
int main()
{
{
PersonPtr pStu = createPerson("deroy");
cout<<"即将离开作用域"<<endl;
}
cout << "main over" << endl;
return 0;
}
ubuntu@VM-16-5-ubuntu:~$ g++ -std=c++11 -o test test.cpp
ubuntu@VM-16-5-ubuntu:~$ ./test
new:deroy
即将离开作用域
use_count=0,call lambda release function
deroy:我该干点什么事情好呢?
子类析构:deroy
父类析构:deroy
main over
std::shared_ptr<Data> dataPtr1(new Data(1)); // Data(1)的引用计数为1
std::shared_ptr<Data> dataPtr2 = dataPtr1; //现在dataPtr1和dataPtr2同时指向Person(1),的引用计数加一
std::cout<<dataPtr1.use_count()<<std::endl; //引用计数为2
std::cout<<dataPtr2.use_count()<<std::endl; //引用计数为2
/*接上面的代码*/
dataPtr1.reset(); //Data(1)的引用计数为1
//dataPtr2.reset();//Data(1)的引用计数为0,Data(1)
#include <iostream>
#include <memory>
using namespace std;
class Person
{
public:
Person(int v) {
value = v;
std::cout << "Cons" <<value<< std::endl;
}
~Person() {
std::cout << "Des" <<value<< std::endl;
}
int value;
};
int main()
{
Person *p5 = new Person(5);
std::shared_ptr<Person> p6(p5);
std::shared_ptr<Person> p7 = p6; //使用赋值共享指针对象的管理
// std::shared_ptr<Person> p7(p5);// logic error
return 0;
}
ubuntu@VM-16-5-ubuntu:~$ g++ -std=c++11 -o test test.cpp
ubuntu@VM-16-5-ubuntu:~$ ./test
Cons5
Des5
后面 weak_ptr
介绍。
成员函数 | 作用 |
---|---|
reset() | 重置智能指针,delete其关联的指针。 |
release() | 不delete关联指针,并返回关联指针。 释放关联指针的所有权,智能指针为空。 |
get() | 仅仅返回关联指针 |
use_count() | 获取引用计数 |
std | 作用 |
---|---|
std::make_shared | 创建 make_shared 对象C++14 |
std::move() | 对象转移 |
·················END·················