《深入应用C++11代码优化与工程级应用》第四章的读书笔记,以及自己写的一些测试demo
第三方库分配的内存一般需要通过第三方库提供的释放接口才能释放,由于第三方库返回的指针一般都是原始指针,用完之后如果没有调用第三方库的释放接口,就很容易造成内存泄露。
例如
void *p = GetHandle()->Create();
//do something
GetHandle()->Realease(p);
用智能指针来管理第三方库的内存就比较方便,不用担心中途返回或者发生异常导致无法调用释放接口的问题。
void *p = GetHandle()->Create();
//do something
std::shared_ptr<void> sp(p, [this](void* p) {GetHandle()->Realease(p); });
将其提炼成函数
std::shared_ptr<void> Guard(void*p)
{
std::shared_ptr<void> sp(p, [this](void* p) {GetHandle()->Realease(p); });
return sp;
}
//在使用时
void* p = GetHandle()->Create();
Guard(p); //危险,这句结束后p就被释放了
//do something
执行Guard§;这句后,函数返回的是一个右值,没有被存储,用完就把p释放了。
可以用宏的方式来解决这个问题:
#define GUARD(p) std::shared_ptr<void> p##p(p, [](void *p){release(p);})
//使用时
void* p = GetHandle()->Create();
GUARD(p); //安全
也可以用unique_ptr来管理第三方的内存:
#define GUARD(p) std::unique_ptr<void> p##p(p, [](void *p){release(p);})
对于宏中的##,其实也很好理解,就是将##前后的字符串连接起来
#define GUARD(p) std::shared_ptr<void> p##p(p, [](void *p){release(p);})
//使用时
void* p = GetHandle()->Create();
GUARD(p); //安全
//会有一个std::shared_ptr<void> pp的智能指针,不信就进行测试。原因去找刚才的#define中有p##p
std::cout << pp.use_count() << std::endl;
为了验证原作者的这些,写一些demo来帮助理解,也有利于更好掌握:
创建一个Base类:
Base.h文件中:
#pragma once
class Base
{
public:
Base();
~Base();
void print();
};
Base.cpp文件中:
#include "Base.h"
#include <iostream>
Base::Base()
{
std::cout << "Base constructor" << std::endl;
}
Base::~Base()
{
std::cout << "Base desctructor" << std::endl;
}
void Base::print()
{
std::cout << "print something" << std::endl;
}
在main.cpp中:
#include "Base.h"
#include <memory>
#include <iostream>
#define GUARD(p) std::shared_ptr<Base> p##p(p, [](Base*p){release(p);})
Base* create()
{
return new Base();
}
void release(Base* base)
{
delete base;
}
std::shared_ptr<Base> Guard(Base *p)
{
std::shared_ptr<Base> sp(p, [](Base*p) {release(p); });
return sp;
}
int main()
{
{
Base* p = create();
std::shared_ptr<Base> sp(p, [](Base*p) {release(p); });
//Guard(p);
//GUARD(p);
//std::cout << "sp.use_count():" << sp.use_count() << std::endl;;
p->print();
}
getchar();
return 0;
}
此时的输出为:
Base constructor
print something
Base desctructor
【修改一】 当我们对main()中修改为:
int main()
{
{
Base* p = create();
//std::shared_ptr<Base> sp(p, [](Base*p) {release(p); });
Guard(p);
//GUARD(p);
//std::cout << "sp.use_count():" << sp.use_count() << std::endl;;
p->print();
}
getchar();
return 0;
}
运行结果:
Base constructor
Base desctructor
print something
发现这时候的p被提前释放了,print something已经是在Base类析构之后做的,此时已经出问题了。
【修改二】将main函数进行修改:
int main()
{
{
Base* p = create();
//std::shared_ptr<Base> sp(p, [](Base*p) {release(p); });
//Guard(p);
GUARD(p);
std::cout << "pp.use_count(): " << pp.use_count() << std::endl;;
p->print();
}
getchar();
return 0;
}
运行结果:
Base constructor
pp.use_count(): 1
print something
Base desctructor
果然如我们所想,一切正常。
参考:
#define中的 #与##