讲讲智能指针的缺点

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

我能想到的
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)即可。


<think>好的,用户让我讲讲模板特化。首先,我需要确定用户的知识背景。他们之前问过内存泄漏的问题,提到了智能指针和系统资源管理,可能有一定的C++基础。现在他们问模板特化,这是一个中级到高级的C++特性,所以需要从基础讲起,但也要深入一些细节。 首先,模板特化分为全特化和偏特化。全特化是针对所有模板参数都指定具体类型的情况,而偏特化则是部分指定,或者针对某种模式的特化。我需要用简单明了的例子来说明两者的区别。 用户可能在面试中被问到这个问题,或者在实际项目中遇到了需要特化模板的情况。他们可能想了解如何根据不同的类型优化代码,或者处理特定类型的特殊逻辑。比如,对于某些类型,通用模板可能效率不高,或者有特殊需求,这时候特化就派上用场了。 接下来,我需要考虑用户可能的疑问点。比如,模板特化和函数重载的区别?什么时候应该用特化而不是重载?可能还需要提到类模板和函数模板在特化上的不同,因为函数模板不支持偏特化,只能用重载代替。 另外,用户可能对实际应用场景感兴趣,比如在标准库中的应用,比如std::vector<bool>的特化。或者在实际项目中如何利用特化来优化性能或处理特殊类型。 还要注意术语的准确性,比如“偏特化”有时也被称为“部分特化”,需要统一说法。同时,代码示例要正确,比如全特化的语法,偏特化的模式匹配例子,比如指针类型或容器类型的特化。 另外,用户可能对特化的使用场景和注意事项不太清楚,比如特化必须出现在通用模板之后,否则会编译错误。或者特化可能导致代码膨胀,需要权衡利弊。 最后,总结模板特化的优缺点和适用场景,帮助用户理解何时使用,并避免常见错误。确保回答结构清晰,逐步展开,从定义到分类,再到应用场景和注意事项,符合用户之前提到的结构化回答需求。</think>好的,我将以结构化方式讲解C++模板特化技术,重点突出核心原理和实际应用场景: 一、模板特化基本概念 🔍 1. **定义**:为特定类型参数提供定制化的模板实现 2. **核心价值**: - 优化特定类型的性能(如指针类型特化) - 处理特殊类型需求(如`void`类型特化) - 增强类型安全性(如禁用某些类型的模板实例化) 二、模板特化分类体系 📚 1. **全特化(Explicit Specialization)** - 语法结构: ```cpp template <> // 空模板参数列表 class/struct 模板名<具体类型列表> { ... }; ``` - 经典案例: ```cpp template<typename T> struct IsPointer { static const bool value = false; }; template<typename T> // 全特化版本 struct IsPointer<T*> { static const bool value = true; }; ``` 2. **偏特化(Partial Specialization)** - 特征:保留部分模板参数未指定 - 类型模式匹配: ```cpp template<typename T, typename U> // 原模板 class MyClass { ... }; template<typename T> // 偏特化版本 class MyClass<T, int> { ... }; // 第二个参数固定为int ``` 三、实战应用场景 💻 1. **类型萃取(Type Traits)** ```cpp template<typename T> struct IsIntegral { static const bool value = false; }; template<> // 全特化版本 struct IsIntegral<int> { static const bool value = true; }; ``` 2. **容器优化(如std::vector<bool>特化)** ```cpp template<typename T> class Vector { /* 通用实现 */ }; template<> // 全特化版本 class Vector<bool> { // 使用位压缩存储的优化实现 }; ``` 3. **算法优化(针对不同迭代器类别)** ```cpp template<typename Iter> void sort(Iter first, Iter last) { // 通用快速排序实现 } template<typename Iter> // 偏特化版本 void sort<random_access_iterator_tag>(Iter first, Iter last) { // 针对随机访问迭代器的优化实现 } ``` 四、特化技术要点 🚩 1. **匹配优先级**:全特化 > 偏特化 > 主模板 2. **函数模板限制**: - 函数模板不支持偏特化(可通过重载实现类似效果) - 类模板支持全特化和偏特化 3. **特化声明位置**:必须出现在主模板定义之后 五、特化 vs 重载 ⚖️ 1. **模板特化**: - 保持相同的模板名称 - 通过参数类型模式匹配触发 2. **函数重载**: - 创建不同签名的函数 - 支持隐式类型转换 六、最佳实践建议 ✅ 1. **优先使用重载**处理函数模板的特殊情况 2. **谨慎使用全特化**(容易破坏泛型设计的统一性) 3. **典型应用场景**: - 标准库类型萃取(`std::is_pointer`) - 数学库精度控制(`float/double`差异处理) - 序列化特殊处理(字符串类型优化) 示例:智能指针删除器特化 ```cpp template<typename T> struct DefaultDeleter { // 主模板 void operator()(T* p) { delete p; } }; template<typename T> struct DefaultDeleter<T[]> { // 偏特化(数组类型) void operator()(T* p) { delete[] p; } }; ``` 通过合理使用模板特化,开发者可以构建出兼具通用性和特殊优化的高质量泛型代码。在实际工程中,建议将特化技术与SFINAE、concepts等现代C++特性结合使用,以提升代码的可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值