C++ SharedPtr 智能指针操作二维数组的细节异同
来源:互联网 发布:联想数据恢复中心 编辑:程序博客网 时间:2024/06/06 01:35
智能指针(以shared_ptr为代表)是现代C++中非常重要的STL类。其使用引用计数机制,能够自动释放内存,从而一定程度上避免了内存泄漏。然而,由于STL库的版本各不相同,不同的shared_ptr实现还是会对使用造成影响。近期,笔者在升级维护一个既有代码的二维数组动态管理时,遇到了一类特殊的情况,特此记录。
二维数组智能指针的编译错误
待升级的源代码一直被认为健壮性很棒,用 GNU C++ 4、Visual C++ 2013 编译时,几乎0警告通过。其使用了大量的shared_ptr在多个线程中传递整块的数据,在7*24小时运行中表现出很强的稳定性,其中一段代码如下:
bool foo (const int N, ...){\\... shared_ptr< int[24] > bar(new int[N][24], [=](int(*p)[24])->void { delete[] p; } );}
foo函数中,定义了一个名为bar的智能指针,指向一个二维数组。第二维包含24个元素,第一维是动态管理的。这段代码很清晰,模板类型为 int[24],释放器的类型为 int(*)[24]。
可是,当升级到GNU C++ 7.2时,情况发生了变化:
error: no matching function for call to 'std::shared_ptr<int [24]>::shared_ptr(int (*)[24])' shared_ptr< int [24] > pt (new int [4096][24]);
这真是非常奇怪!相同的代码,在Visual C++ 2017编译器下、GNU-C++ 4编译器下均是正常的。
shared_ptr实现异同
为了找到原因,我们首先看看成功编译通过的版本。
GNU C++ 4 附带实现:
template<typename _Tp> class shared_ptr : public __shared_ptr<_Tp> { public: constexpr shared_ptr() noexcept : __shared_ptr<_Tp>() { } shared_ptr(const shared_ptr&) noexcept = default; template<typename _Tp1> explicit shared_ptr(_Tp1* __p) : __shared_ptr<_Tp>(__p) { } template<typename _Tp1, typename _Deleter> shared_ptr(_Tp1* __p, _Deleter __d) : __shared_ptr<_Tp>(__p, __d) { } };
Visual C++ 2017 附带实现:
template<class _Ty> class shared_ptr : public _Ptr_base<_Ty> { // class for reference counted resource managementpublic: typedef shared_ptr<_Ty> _Myt; typedef _Ptr_base<_Ty> _Mybase; template<class _Ux> explicit shared_ptr(_Ux *_Px) { // construct shared_ptr object that owns _Px _Resetp(_Px); } template<class _Ux, class _Dx> shared_ptr(_Ux *_Px, _Dx _Dt) { // construct with _Px, deleter _Resetp(_Px, _Dt); } }
而编译出现错误的 GNUC++ 7.2附带 STL实现版本如下:
template<typename _Tp> class shared_ptr : public __shared_ptr<_Tp> { public: template<typename _Yp, typename = _Constructible<_Yp*>> explicit shared_ptr(_Yp* __p) : __shared_ptr<_Tp>(__p) { } template<typename _Yp, typename _Deleter, typename = _Constructible<_Yp*, _Deleter>> shared_ptr(_Yp* __p, _Deleter __d) : __shared_ptr<_Tp>(__p, std::move(__d)) { }
该定义牵扯到一系列的问题,主要是存在于复杂的typename模板操作上。貌似 类型 int[24] 不是一种具有一般可构造特性的类型。但是由于该版本STL实现非常复杂,暂时没有时间阅读,只能通过折中的办法来处理:降低编译器版本。
C++语言标准的碎碎念
本人熟练使用C/C++语言已经至少15年,目睹了C++语言的不断变化,尤其是近几年,很多激进的特性被引入进来。有时觉得,C++标准委员会对这种语言的发展,有点剑走偏锋了。这种语言的精髓是在于强大的无所不包的类库。从图像处理到视频剪辑,从信号处理到模式识别,开源的资源包罗万象。标准委员会最应该把精力投入到支持现代化类库发展上去,比如在语言周边,设立一两个标准框架库的名分(如Qt、boost);其次,应该详细的测试并审核各种代码片段的行为,让不同的编译器的编译行为、产生的代码行为尽可能一致。解决了这两个问题,再去研究拓展语言特性,就游刃有余了。
不知道委员会了不了解,很多非计算机专业的工程师从不自己写类。他们只是把C++标准、准标准(如大公司的类库)提供的类库当做int, double 一样的简单类型来用而已。正如一个嵌入式工程师,可能使用整套Qt类库,但仍旧采用面向过程的风格完成串口继电器控制一样,他们其实是用C++的便捷类库继续开发C程序。因此,语言的编译器一致性是最关键的,而不是能不能写出酷炫的代码。
这应该是个问题,已经提交了一个maillist给GCC
https://gcc.gnu.org/ml/libstdc++/2017-10/msg00020.html
希望后续有结果
最终回复
很快收到了答复:
No, it's because in C++11 and C++14 shared_ptr was not designed to beused with arrays. In C++17 arrays are fully supported, but in a waythat is incompatible with your code.It will work if you use shared_ptr<int[]24]> because that's actually ashared_ptr that owns a 2D array.
我们采用下面的代码,就编译通过了:
shared_ptr< int[][24] > pt ( new int[4096][24], [=](int (*p)[24])->void{delete [] p;} );
- C++ SharedPtr 智能指针操作二维数组的细节异同
- Poco SharedPtr 智能指针处理数组方式
- 智能指针SharedPtr
- 智能指针3---SharedPtr
- 智能指针 AutoPtr ScopedPtr SharedPtr
- 智能指针—AutoPtr,ScopedPtr,SharedPtr的模拟实现
- C/C++指针和数组的异同
- 用指针操作二维数组 C 语言
- C语言:使用指针操作二维数组
- 指针操作二维数组
- C语言,二维数组时候的指针
- C 二维数组与指针的关系
- C/C++指向二维数组的指针
- C语言中二维数组、二维指针、指向指针的数组、指向数组的指针
- 引用计数的智能指针——sharedptr的模拟实现
- 小细节!!!!(二维树状数组的相关操作)
- C/C++二维数组的参数传递与二维指针
- C++之数组与指针的异同
- U3D基础教程重读 基础编辑和导入文件
- C++异常机制:引用原因与使用原则
- U3D角色动画
- 查看webpack打包后的js报错位置
- 适配 iOS 11 & iPhone X
- C++ SharedPtr 智能指针操作二维数组的细节异同
- 设计模式C++(Factory Method工厂方法模式)
- 利用bin-log文件特点配置读写分离
- U3D物理引擎
- python--leetcode637. Average of Levels in Binary Tree
- Scry.info技术分享——ScryDB简介
- U3D光源烘培光照贴图和light probes
- java 给数字加上单位'万'
- PAT 甲级 1084. Broken Keyboard (20)