指针强转的时候要小心啊!

今天我的程序遇到了一个BUG,很蹊跷。

ACE有一个ACE_Service_Repository单件,相当于一个bean container那样的东西。我把一些object在启动的时候注册进去,然后在运行的时候根据名字查找。于是就解决了两个问题:

  1. 以名称查找的方式进行依赖注入

  2. 被查找的对象,可以单独编译在另一个so中,动态加载。

但是我用的时候遇到了BUG,我的出问题的代码如下:

ACE_Service_Type const *svcp = 0; 
    if (-1 == ACE_Service_Repository::instance ()->find (ACE_TEXT ("MyDbEnv"), 
                                                       &svcp)) {        
        throw new std::runtime_error("cannot find MyDbEnv Impl"); 
    }

MyDbEnv* env=(MyDbEnv*)svcp->type()->object();

env->openDatabase("…");

运行的时候,vc告诉我,esp寄存器坏了。我纳闷了好一半天。

向ACE_Service_Repository注册对象首先要用这个宏定义一个工厂方法,

ACE_FACTORY_DEFINE (ACE_Local_Service, MyDbEnv)

其中ACE_FACTORY_DEFINE的定义如下:

# define ACE_FACTORY_DEFINE(CLS,SERVICE_CLASS) \ 
void ACE_MAKE_SVC_CONFIG_GOBBLER_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) (void *p) { \ 
  ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object * _p = \ 
    static_cast< ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object *> (p); \ 
  ACE_ASSERT (_p != 0); \ 
  delete _p; } \ 
extern "C" CLS##_Export ACE_VERSIONED_NAMESPACE_NAME::ACE_Service_Object *\ 
ACE_MAKE_SVC_CONFIG_FACTORY_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS) (ACE_Service_Object_Exterminator *gobbler) \ 
{ \ 
  ACE_TRACE (#SERVICE_CLASS); \ 
  if (gobbler != 0) \ 
    *gobbler = (ACE_Service_Object_Exterminator) ACE_MAKE_SVC_CONFIG_GOBBLER_NAME(ACE_VERSIONED_NAMESPACE_NAME,SERVICE_CLASS); \ 
  return new SERVICE_CLASS; \ 
}

这个问题就在于,我new了一个MyDbEnv(),它给调用者返回的指针是ACE_Service_Object *。所以ACE_Service_Repository里面存的也是ACE_Service_Object *。但是,它的ACE_Service_Type的type().object()方法返回的是void*。这个问题相当于这样:

Parent* p =new Child(); 
void* value=p; 
Child* c=(Child*)value;

在最后一次指针转换的时候,因为丢失了类型信息,所以没有对指针做相应的偏移。所以前面那段有BUG的代码应该改成:

     ACE_Service_Type const *svcp = 0; 
    if (-1 == ACE_Service_Repository::instance ()->find (ACE_TEXT ("MyDbEnv"), 
                                                       &svcp)) {        
        throw new std::runtime_error("cannot find MyDbEnv Impl"); 
    }     
    ACE_Service_Object* so=(ACE_Service_Object*)svcp->type()->object(); 
    MyDbEnv* env=dynamic_cast<MyDbEnv*>(so);

最后,我发现一个有趣的东西。我又发现了一种偷变量的方法:

#include <iostream>

//the object of this type is immutable,it cannot be changed after constructed。 
class A1{ 
private: 
  int value; 
public: 
  A1(int v):value(v){}; 
  void printValue(){ 
    std::cout<<value<<std::endl; 
  } 
};


class A2{ 
public: 
  int value; 
  A2(int v):value(v){}; 
  void printValue(){ 
    std::cout<<value<<std::endl; 
  } 
};

int main(int argc,char* argv[]){ 
  A1* a=new A1(10); 
  A2* b=(A2*)a; 
  b->value=15; 
  a->printValue(); //should be 15。 
  return 0; 
}

Sometimes, immutable is not really immutable!

此博客中的热门博文

少写代码,多读别人写的代码

在windows下使用llvm+clang

tensorflow distributed runtime初窥