ddddfang's Blog.

cpp-shared_ptr

字数统计: 1.2k阅读时长: 4 min
2019/03/08 Share

对于拥有构造函数的对象而言 new ABC 与 new ABC() 效果等同,但对于内置类型而言,eg. new int 指向的int未初始化,而 new int()指向的int采用值初始化(0)
动态内存管理3个常见问题:
1.忘记 delete
2.使用以及释放的内存,释放内存后将其置为 nullptr 是个好习惯,防止野指针,但是保护有限,比如可能存在多个指针指向相同的内存
3.重复delete(p437)
坚持只使用智能指针可以避免所有这些问题! 智能指针和内置指针最好不要混用(因为一旦智能指针接管了内置指针,就可能在某些时候释放他)!

智能指针类能记录有多少个用户通过 shared_ptr 指向了相同的对象,并在无 shared_ptr 指向对象时,将对象释放
(机制很像 garbage collect,看起来是内置指针wrap了一层,大家都使用wrapped管理结构access内置指针指向的对象,
wrapped管理结构每个用户分配一个,拷贝或赋值的时候会先更新wrapped管理结构,然后分裂出一个新的wrapped管理结构传出去)

shared_ptr p1; //将被初始化为空指针
shared_ptr p2(new int(1024)); //p2指向一个值为1024的int(或者说,p2接管了内置指针),用来构造智能指针的内置指针必须指向动态内存,因为只能指针指不定什么时候就用delete将其释放啦
shared_ptr p3 = new int(1024); //错误的! 因为c++没有提供内置指针到智能指针的隐式转换

caffe 中智能指针使用例子:
vector<shared_ptr<Layer > > layers_;
for (int layer_id = 0; layer_id < param.layer_size(); ++layer_id) {
layers_.push_back(LayerRegistry::CreateLayer(layer_param));
}
shared_ptr diff_; //梯度信息
diff_.reset(new SyncedMemory(capacity_ * sizeof(Dtype))); //reset()可能会触发智能指针原来指向那块内存的释放操作

智能指针调用 get() 将返回其管理的内置指针,但是:
1.不准使用内置指针的代码使用delete将其释放(这是智能指针干的活)
2.不准用内置指针再去构造另一个智能指针(两个智能指针管理一个内置指针会混乱的!我怎么知道另一个智能指针是否已经将动态内存给释放了呢??)

智能指针可以确保即使异常发生(在释放资源的代码之前),资源也可以被正确释放(p441)
智能指针管理的类需要一个析构函数,且需要正确的在析构函数中释放资源,否则智能指针也帮不了你了

p438 表12.3很有用
p443 智能指针注意事项总结
https://www.cnblogs.com/diysoul/p/5930396.html
https://www.2cto.com/kf/201612/580580.html
https://www.cnblogs.com/lsgxeva/p/7788061.html

如果限制 shared_ptr 不可以进行普通的拷贝和赋值,那就是 unique_ptr ,unique_ptr 只允许某个用户独占,可以转移给其他用户但是不可以俩用户共享

weak_ptr 指向一个 shared_ptr 管理的对象,但是不会触发 shared_ptr 更改引用计数,即 一旦最后一个指向对象的 shared_ptr 被销毁,对象就被释放,
即使还有 weak_ptr 指向这个对象

std::unique_ptr up1(new int(11)); // 无法复制的unique_ptr
//unique_ptr up2 = up1; // err, 不能通过编译
std::unique_ptr up3 = std::move(up1); // 现在p3是数据的唯一的unique_ptr
//std::cout << up1 << std::endl; // err, 运行时错误
up3.reset(); // 显式释放内存
up1.reset(); // 不会导致运行时错误
//std::cout <<
up3 << std::endl; // err, 运行时错误

std::unique_ptr up4(new int(22));
up4.reset(new int(44)); //“绑定”动态对象
std::cout << *up4 << std::endl; // 44
up4 = nullptr;//显式销毁所指对象,同时智能指针变为空指针。与up4.reset()等价

std::unique_ptr up5(new int(55));
int p = up5.release(); //只是释放控制权,不会释放内存
std::cout <<
p << std::endl;
//cout << *up5 << endl; // err, 运行时错误
delete p; //释放堆区资源

void check(std::weak_ptr &wp)
{
std::shared_ptr sp = wp.lock(); // 转换为shared_ptr
if (sp != nullptr)
{
std::cout << “still: “ << *sp << std::endl;
}
else
{
std::cout << “still: “ << “pointer is invalid” << std::endl;
}
}

std::shared_ptr sp1(new int(22));
std::shared_ptr sp2 = sp1;
std::weak_ptr wp = sp1; // 指向shared_ptr所指对象

std::cout << “count: “ << wp.use_count() << std::endl; // count: 2
std::cout << sp1 << std::endl; // 22
std::cout <<
sp2 << std::endl; // 22
check(wp); // still: 22

sp1.reset();
std::cout << “count: “ << wp.use_count() << std::endl; // count: 1
std::cout << *sp2 << std::endl; // 22
check(wp); // still: 22

sp2.reset();
std::cout << “count: “ << wp.use_count() << std::endl; // count: 0
check(wp); // still: pointer is invalid

CATALOG