讲讲智能指针的缺点

智能指针有什么不足之处?

我能想到的
1 循环引用
2 基于引用计数的一些性能损耗

还有其他的缺点吗?相对比来说GC比智能指针又有什么优势呢

9 人赞同了该回答
智能指针的设计理念是没有问题的,各位说风格不一致问题的,是因为还在用老的理念用新东西。
和普通指针相比,智能指针通过引用计数,实现了资源回收。智能指针是为了减轻程序员直接管理内存。和new混杂使用是习惯问题,不是智能指针的问题。
围绕引用计数,带来轻微的性能损失,如多线程下,引用计数的管理。另一个是,类型转换问题。
大家需要的是,与时俱进,而不是用老眼光看待新东西。
编辑于 2017-06-13

21 人赞同了该回答

最大的不足之处就是:本来分明应当做成语言特性的东西,为了和C保持兼容性,必须TMD做成一个库。

C++大概一半左右的蛋疼,都是因为这个原因。

20 人赞同了该回答
1.智能指针只能表示所有权,如果遇到某些复杂的数据结构,或者所有权不明确的场景,还是得裸指针来。
2.虽然它本身不是侵入式数据结构,但实际上在代码设计时,一处用到智能指针,便处处用到智能指针,可算是一种“感染性”。考虑到不同的智能指针无法混用,标准库恐怕和老代码的调和程度也很差。
30 人赞同了该回答

shared_ptr想用成瓶颈是不可能的,C#的new之所以比C++快也是因为人家内存池做的好,而不是因为少了interlocked refcount操作。最大的不足之处就是你得好好区分shared_ptr和unique_ptr还要避免连成环。你看C#就没有这个问题,想怎么写就怎么写,程序员什么都不懂也没关系。

编译器无法提示 unique_ptr 被 move 之后又被使用了。这种错误使用不会产生任何编译错误或警告。

4 人赞同了该回答
循环引用可以通过多注意一下或者循环引用检查或者弱引用来解决。
至于性能,智能指针性能主要耗费在内存分配和释放上,适当加个内存池可以事半功倍。这个可以参考我写的Mozart Any,内部资源是引用计数器持有的,加了内存池之后性能提高了至少30%。
RC相对于GC优点在于回收开销是均摊的,如果不用并发回收的话全面停顿/短停顿GC对于要求实时性的程序来说是灾难性的。
5 人赞同了该回答

1. 语法丑陋
尤其是new对象的异常控制和shared,weak混用都时候, 语法丑陋让人不愿意使用。
而且智能指针并不智能,还是需要人去精心控制,并不能像java,c#完全不需要关心析构。

丑是最大的bug, 为了屁大点的事情,需要考虑一堆问题,比手动new/free还麻烦。

2.破坏c++原则
c++有个原则,不使用会带来额外开销的特性。
但是智能指针不管是否多线程情况,都使用原子操作。普通指针可以常驻register不影响inline优化。
而且shared ptr的计数器地址和对象指针地址并不在一起(两次new),在cache上也是不友好的。
(评论区有人提到make-shared可以保证内存连续)


觉得右值引用才是真正的c++版智能指针
跨语言时十分麻烦,比如lua,还得转换成裸指针userdata传过去中转一下再传回来,得保证丢失引用后不被释放,这是很蛋疼的事情。

1 智能指针比裸指针多敲字符,太丑了。
2 所有权系统与数据结构天生不太相合,不过这也说不上缺点。

总结:想要既美观又强大的智能指针吗?快来用Rust啊。(屎蛋口音)

我觉得最大的不足,就是标准出来的太晚

特别是有时候需要异步的时候,传递对象在一个地方new,另一个地方delete,我觉得很不美观

在栈上new出空间之后 在智能指针真正接管裸指针之前 如果出现异常 会内存泄露吧

1 人赞同了该回答

C++11新的标准所有的标准,我都推荐在工程中使用,但是智能指针除外。
1. RAII想法是好的,但是并不是所有都能控制的。
2. 智能指针的传染性很大,要替换的话,就要替换所有的指针,风险很大。
3. 智能指针如果出现相互应用(就是循环)很可怕。

1. 裸指针很好控制(使用历史久),只要按照规范来,不会出现问题,即使出现问题也比较好修改。

举个循环引用的例子

-----------------------------------------------------------------------------------------------------------------------

class  B;
class  A
{
public :
  shared_ptr<B> m_b;
};
 
class  B
{
public :
  shared_ptr<A> m_a;
};
 
int  main()
{
   while  ( true )
  {
    shared_ptr<A> a( new  A); //new出来的A的引用计数此时为1
    shared_ptr<B> b( new  B); //new出来的B的引用计数此时为1
    a->m_b = b; //B的引用计数增加为2
    b->m_a = a; //A的引用计数增加为2
  }
 
   //b先出作用域,B的引用计数减少为1,不为0,所以堆上的B空间没有被释放,且B持有的A也没有机会被析构,A的引用计数也完全没减少
 
   //a后出作用域,同理A的引用计数减少为1,不为0,所以堆上A的空间也没有被释放
 
}

如此一来,A和B都互相指着对方吼,“放开我的引用!“,“你先发我的我就放你的!”,于是悲剧发生了。

 

所以在使用基于引用计数的智能指针时,要特别小心循环引用带来的内存泄漏,循环引用不只是两方的情况,只要引用链成环都会出现问题。当然循环引用本身就说明设计上可能存在一些问题,如果特殊原因不得不使用循环引用,那可以让引用链上的一方持用普通指针(或弱智能指针weak_ptr)即可。


  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值