于头文件<memory>
1. shared_ptr实现共享拥有(shared ownership),标准库还提供了weak_ptr bad_weak_ptr和enable_shared_from_this等辅助类
2. unique_ptr实现独占式拥有(exclusive ownership/strict ownership),
3. 特点
shared_ptr和weak_ptr内部需额外的辅助对象(引用计数器等),因此无法完成一些优化操作
unique_ptr不需要这些额外的开销(unique_ptr特殊的构造和析构、copy语义的消除),unique_ptr消耗的内存和native pointer相同,还可使用function object(包括lambda)作为deleter达成最佳优化,甚至零开销。
smart pointer并不保证线程安全,虽然它有适用某些保证。
目录
share_ptr
- shared_ptr基本使用
//1. 直接初始化
shared_ptr<string> test(new string("nico"));
shared_ptr<string> test{new string("nico")};
//2. 使用便捷函数make_shared(),快、安全、使用一次分配
shared_ptr<string> test = make_shared<string>("nico");
//3. 先声明,然后赋值(需使用reset(),不能使用赋值运算符)
shared_ptr<string> test;
test = new string("nico"); //Error
test.reset(new string("nico"));//OK
//错误使用
int* p = new int;
std::shared_ptr<int> sp1(p);
std::shared_ptr<int> sp2(p); //Error:two shared pointers manage allocated int
//正确使用
std::shared_ptr<int> sp1(new int);
std::shared_ptr<int> sp2(sp1);
线程安全(Thread-Safe)的Shared Pointer接口
shared pointer并非线程安全,通常为避免data race须使用如mutex或lock等。但当一个线程修改对象时,其他线程读取其使用次数并不会造成data race,虽然可能读到的值不是最新的。
对付Array
shared_ptr提供的default deleter调用的是delete,不是deleter[]。因此只有当shared pointer拥有“由new建立的单一对象”,default deleter才适用
std::shared_ptr<int> p(new int[10]); //Error,but compiles
std::shared_ptr<int> p(new int[10], //new[]一个array of object须定义deleter
[](int* p) {
delete[] p;
});
//使用为unique_ptr提供的辅助函数作为deleter(内部调用了delete[])
std::shared_ptr<int> p(new int[10],
std::default_delete<int[]>());
处理共享内存
#include <memory> //for shared_ptr
#include <sys/mman.h> //for shared memory
#include <fcntl.h>
#include <unistd.h>
#include <cstring> //for strerror()
#include <cerrno> //for errno
#include <string>
#include <iostream>
/**
*@brief 卸除(detach) shared memory
*/
class SharedMemoryDetacher {
public:
void operator() (int* p) {
std::cout<<"unlink /tmp1234"<<std::endl;
if (shm_unlink("/tmp1234") != 0) {
std::cerr<<"OOPS: shm_unlink() failed"<<std::endl;
}
}
};
/**
* @brief 取得并附着(attach) shared memory
*/
std::shared_ptr<int> getSharedIntMemory (int num) {
void* mem;
int shmfd = shm_open("/tmp1234", O_CREAT|O_RDWR, S_IRWXU|S_IRWXG);
if (shmfd < 0) {
throw std::string(strerror(errno));
}
if (ftruncate(shmfd, num*sizeof(int)) == -1) {
throw std::string(strerror(errno));
}
mem = mmap(nullptr, num*sizeof(int), PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
if (mem == MAP_FAILED) {
throw std::string(strerror(errno));
}
//SharedMemoryDetacher将在最后一次被使用时调用
// return std::shared_ptr<int>(static_cast<int*>(mem), SharedMemoryDetacher());
//使用lambda
return std::shared_ptr<int>(static_cast<int*>(mem),
[](int* p){
std::cout<<"unlink /tmp1234 "<<std::endl;
if (shm_unlink("/tmp1234") != 0) {
std::cerr<<"OOPS: shm_unlink() failed"<<std::endl;
}
});
}
int main() {
//get and attach shared memory for 100 ints
std::shared_ptr<int> smp(getSharedIntMemory(100));
//init the shared memory
for (int i = 0; i < 100; ++i) {
smp.get()[i] = i*42;//通过get()获得被shared_ptr包裹(wrapped)的内部指针
}
//deal with shared memory somewhere else
std::cout<<"<return>"<<std::endl;
std::cin.get();
//release shared memory here:
smp.reset();
return 0;
}
weak_ptr
- 下面2种情况shared_ptr将会遇到问题
- cyclic reference(环式指向)。如果两个对象使用shared_ptr互相只想对方,每个对象的use_count()都为1,反而都无法释放。
- 在你“明确的只是想共享但不愿拥有”某对象的情况下。你要的语义是:reference的寿命比其所指对象的寿命更长。
- class wake_ptr允许你“共享但不拥有”对象(use_count()返回的是对象被shared_ptr拥有的次数),即在最后一个拥有该对象的shared_ptr失去拥有权后,weak_ptr会自动成空(empty),class weak_ptr只提供“接受一个shared_ptr”的构造函数。
- 不能使用操作符*和->访问weak_ptr指向的对象,而必须另外建立一个shared_ptr,(weak_ptr只能用来创建、复制、赋值weak pointer,以及转换为一个shared pointer或检查自己是否指向某对象)基于下面2个理由
- 在wak pointer之外建立一个shared pointer检查是否存在一个相应的对象。如果不存在,将会抛出异常或。。。
- 当指向的对象正被处理时,shared pointer无法被释放
#include <iostream>
#include <string>
#include <vector>
#include <memory>
class Person {
public:
std::string name;
std::shared_ptr<Person> mother;
std::shared_ptr<Person> father;
// std::vector<std::shared_ptr<Person>> kids; //出问题,每个Person的析构不会被调用
std::vector<std::weak_ptr<Person>> kids;//parent到kids为weak_ptr, kids到parent为shared_ptr
Person(const std::string& n,
std::shared_ptr<Person> m = nullptr,
std::shared_ptr<Person> f = nullptr)
: name(n), mother(m), father(f) {
}
~Person() {
std::cout<<"delete "<<name<<std::endl;
}
};
std::shared_ptr<Person> initFamily(const std::string& name) {
std::shared_ptr<Person> mom(new Person(name+"'s mom"));
std::shared_ptr<Person> dad(new Person(name+"'s dad"));
std::shared_ptr<Person> kid(new Person(name, mom, dad));
mom->kids.push_back(kid);
dad->kids.push_back(kid);
return kid;
}
int main() {
std::shared_ptr<Person> p = initFamily("nico");
// p->mother->kids[0]->name; //Error,weak_ptr不能使用操作符*和->
p->mother->kids[0].lock()->name;
std::cout<<"nico's family exists"<<std::endl;
std::cout<<"- nico is shared "<<p.use_count()<<" times"<<std::endl;
std::cout<<"- name of 1st kid of nico's mom:"<<p->mother->kids[0]->name<<std::endl;
p = initFamily("jim");
std::cout<<"jim's family exists"<<std::endl;
return 0;
}
unique_ptr
C++11起开始提供,是一种在异常发生时可帮助避免资源泄露的smart pointer, 确保一个对象和其相应资源同一时间只被一个pointer拥有。
使用普通指针
因为显示获得资源,不与任何对象捆绑,所以必须被明确释放。但程序若在delete前发生异常将导致内存泄漏(资源泄漏),而使用unique_ptr则不论程序正常或异常结束都能够实现自动销毁。
/**
*@brief 以new和delete创建和销毁对象
*/
void f() {
ClassA* ptr = new ClassA; //create an object explicitly
... //perform some operations
delete ptr; //clean up(destory the object explicitly)
}
//为避免资源泄露
void f() {
ClassA* ptr = new ClassA; //create an object explicitly
try {
... //perform some operations
}
catch(...) {
delete ptr; //clean up
throw; //throw the exception
}
delete ptr; //clean up normal
}
使用unique_ptr
使用*提领(dereference)指向对象,操作符->用来访问成员
//初始化
std::unique_ptr<int> ptr = new int; //Error
std::unique_ptr<int> ptr1(new int); //OK
std::unique_ptr<int> ptr2(ptr1); //Error, unique_ptr不支持copy构造和assignment
std::unique_ptr<int> ptr3(std::move(ptr1));//Ok,ptr1将拥有权移交给ptr3
std::unique_ptr<int> ptr4;
ptr4 = ptr1; //Error,no possible
ptr4 = std::move(ptr1);//ok,不能共享,但可以转移拥有权
//没有任何2个unique_ptr以同一个pointer作为初值
std::string* sp = new std::string("hello");
std:unique_ptr<std::string> up1(sp);
std:unique_ptr<std::string> up2(sp); //Error:up1 and up2 own same data
std::unique_ptr<int> ptr; //ptr此时不拥有对象,为空,ptr == nullptr和ptr.reset()同样置空
ptr.reset(new int);
//调用release()
std::unique_ptr<std::string> up(new std::string("nico"));
...
std::string* sp = up.release(); //up lose owner ship
if (up) { ... } //检查unique_ptr是否拥有对象
if (up != nullptr) { ... } //检查unique_ptr是否拥有对象
if (up.get() != nullptr) { ... } //检查unique_ptr是否拥有对象
from book《C++标准库》第5章
来源:CSDN
作者:Adenium_
链接:https://blog.csdn.net/shanxihqls/article/details/104633456