问题描述

今天在帮同事解决问题时,发现了这个比较有意思的现象,特记录下来备忘。

问题是这样的,同事开发的是应用程序动态库模块,通过应用的框架中以接口方式供外部使用。然后他想对这些接口生命周期进行控制,从语法角度上约束使用者使用的手段。因此他作出了以下修改:

1.增加接口的析构函数,并将析构函数设定为保护级别

2.返回接口的函数用shared_ptr的形式返回

具体代码示例

// 测试接口
struct IAA
{
virtual void Release() = 0;
protected:
virtual ~IAA(){}
}; // 对象删除器
struct HelpDeleteIAA
{
void operator()(IAA* pAA)
{
if (NULL!=pAA)
{
pAA->Release();
}
}
}; class CAA : public IAA
{
public:
CAA()
{
}
virtual ~CAA()
{
}
virtual void Release()
{
delete this;
}
}; typedef std::tr1::shared_ptr<IAA> SPIAA; // 测试创建
SPIAA helpIAA(bool bFlag)
{
if (bFlag)
{
return SPIAA(new CAA, HelpDeleteIAA());
}
return SPIAA(static_cast<IAA*>(NULL));
} int main()
{
SPIAA spAA = helpIAA(); // 测试使用
return 0;
}

写完以后兴冲冲的一编译,傻眼了,提示是不能访问IAA::~IAA()的析构接口。可是在代码中明显指定了删除器啊?百思不得其解。。。

问题原因分析

经过调试后发现问题出现在helpIAA()的函数中,由于智能指针shared_ptr()是一个模版,满足模版推导的过程,而在helpIAA()函数中用到了两种函数构造原型,猜测可能是编译过程中对该模版推导顺序影响了最后产生的结果。

解决方案

将helpIAA()函数的返回代码

return SPIAA(static_cast<IAA*>(NULL));

修改为

return SPIAA(static_cast<IAA*>(NULL), HelpDeleteIAA());

然后执行编译,编译器顺利编译通过了。

总结

以上的问题原因推断只是我个人的一点看法,如果不正确的地方欢迎各位斧正。

shared_ptr模版推导的问题的更多相关文章

  1. C++ Template之函数模版

    函数模版的定义: template <typename T> T const& max(const T& a,const T b) { return a > b ? ...

  2. Effective Modern C++翻译(7)-条款6:当auto推导出意外的类型时,使用显式的类型初始化语义

    条款6:当auto推导出意外的类型时,使用显式的类型初始化语义 条款5解释了使用auto来声明变量比使用精确的类型声明多了了很多的技术优势,但有的时候,当你想要zag的时候,auto可能会推导出了zi ...

  3. C++ Template之类模版

    类模版的定义和声明都和函数模版类似: 代码如下: template <typename T> class Stack { public: void push(const T&); ...

  4. 一个适用于层级目录结构的makefile模版

    今天写了个层次化的Makefile模版,用来自动化编译项目,这个模版应当包含以下功能: 适用于层次化结构,Makefile主要内容都放在顶层目录下的Makefile.env中,子层Makefile包含 ...

  5. 理解shared_ptr<T> ---2

    1.引用计数字段不能放在资源管理类中.我们的解决办法是,把引用计数和资源绑在一起,进行二次封装.但是这样存在一个大问题,不同类型的资源管理类不能兼容.也就是说,shared_ptr<Dog> ...

  6. c++ lambda返回类型自动推导的一些需要注意的地方

    一句话,lambda返回类型自动推导走的是auto,而不是decltype,注意. class ObjectA { public: ObjectA() { val_ = ++g; } ObjectA( ...

  7. [C++ 2011 STL (VS2012 Update4) 源代码阅读系列(2)]熟悉一些宏定义和模版偏特化或叫模版专门化

    [C++ 2011 STL (VS2012 Update4) 源代码阅读系列(2)]熟悉一些宏定义和模版偏特化或叫模版专门化 // point_test.cpp : 知识点练习和测试,用于单步调试,跟 ...

  8. Cocos2d-x3.0模版容器具体解释之二:cocos2d::Map&lt;K,V&gt;

    1.概述: 版本号: v3.0 beta 语言: C++ 定义在 "COCOS2DX_ROOT/cocos/base" 路径下的 "CCMap.h" 的头文件里 ...

  9. 智能指针auto_ptr & shared_ptr

    转载:智能指针auto_ptr 很多人听说过标准auto_ptr智能指针机制,但并不是每个人都天天使用它.这真是个遗憾,因为auto_ptr优雅地解决了C++设计和编码中常见的问题,正确地使用它可以生 ...

随机推荐

  1. VS2008 如何将Release版本设置可以调试的DEBUG版本

    VS2008 如何将Release版本设置可以调试的DEBUG版本 只需设置三个部分: 项目->属性->C/C++->General->Debug Information Fo ...

  2. linux下 ls -l 命令显示结果每一列代表什么意思

    第一个栏位,表示文件的属性.Linux的文件基本上分为三个属性:可读(r),可写(w),可执行(x).但是这里有十个格子可以添(具体程序实现时,实际上是十个bit位).第一个小格是特殊表示格,表示目录 ...

  3. 什么是WEBserver? 经常使用的WEBserver有哪些?

    地址:http://www.mamicode.com/ 什么是WEBserver? 经常使用的WEBserver有哪些? 一.什么是WEBserver Webserver能够解析HTTP协议.当Web ...

  4. C#中的基元类型、值类型和引用类型

    C# 中的基元类型.值类型和引用类型 1. 基元类型(Primitive Type) 编译器直接支持的类型称为基元类型.基元类型可以直接映射到 FCL 中存在的类型.例如,int a = 10 中的 ...

  5. Redis的事务功能详解

    Redis的事务功能详解 MULTI.EXEC.DISCARD和WATCH命令是Redis事务功能的基础.Redis事务允许在一次单独的步骤中执行一组命令,并且可以保证如下两个重要事项: >Re ...

  6. main函数的两个参数

    #include "stdio.h" int main(int argc ,char **argv) { printf("argc = %d \n",argc) ...

  7. Linux - ubuntu中vi不能正常使用方向键与退格键的问题

    一度怀疑是键盘坏了! 之前安装solaris也是这个问题! 重新安装vim就可以了! $sudo apt-get remove vim-common $sudo apt-get install vim

  8. python_如何通过twisted实现数据库异步插入?

    如何通过twisted实现数据库异步插入? 1. 导入adbapi 2. 生成数据库连接池 3. 执行数据数据库插入操作 4. 打印错误信息,并排错 #!/usr/bin/python3 __auth ...

  9. sping中防止定时任务多处运行解决方法

    @Servicepublic class TimerJobService implements LzhTimerJobDao{ Logger logger = LoggerFactory.getLog ...

  10. java日志概述和原理

    OK,现在我们来研究下Java相关的日志. 日志记录是应用程序运行中必不可少的一部分.具有良好格式和完备信息的日志记录可以在程序出现问题时帮助开发人员迅速地定位错误的根源.对于开发人员来说,在程序中使 ...