Monthly Archives: April 2012

关于C++里”Pure Virtual Function Called”的问题

前几天项目里遇到一个crash的bug,直接原因code执行时报了一个”pure virtual function called!”的错,然后挂了。
直觉上来说pure virtual function是在编译阶段就会报错的,不应该出现这样的问题。但问题既然出现了,必然是某个地方真的调用到了纯虚函数。这个问题挺有趣,搞定之后决定记录下来。

Google之,第一个结果就是最完美地解释这个问题产生的原因的。http://www.artima.com/cppsource/pure_virtual.html 不过这里稍微再解释一下。

产生这个问题的原因主要有二:
1) 在基类的构造函数里调用了纯虚函数,这个很容易理解,很显然俺们的项目里不会有这种低级错误,否则一跑就crash… 总之,这个错误就忽略了;
2) 某个继承类的对象调用一个虚函数时,这个对象已经被析构了,这时可能是内存错误,也可能是pure virtual function called

具体点,上code:

class Base
{
public:
  virtual ~Base() { sleep(1); }
  virtual void DoIt() const = 0;
};

class Derived : public Base
{
public:
  virtual ~Derived() { /*sleep(1);*/ }
  virtual void DoIt() const {
    std::cout<<"Derived::DoIt()"<<std::endl;
  }
};

void* Task(void* const p)
{
  const Base * const b = reinterpret_cast<const Base*>(p);
  while (1) {b->DoIt(); usleep(50000);}
  return NULL;
}

int main()
{
  pthread_t t;
  Derived * const b = new Derived();
  pthread_create(&t, NULL, Task, (void*)b);

  delete b;
  pthread_join(t, NULL);
}

执行结果(gcc版本4.6.1):

pure virtual method called
terminate called without an active exception
Aborted

稍微解释一下:
1) Base的析构函数里会sleep 1秒;
2) 线程里不停地调用 b->DoIt()函数;
3) 在delete b之后,继承的类Derived已经析构,而Base还存在,因此这时去调用DoIt()时就出现了pure virtual method called的error

如果想做backtrace,可以实现自己的handler。在gcc里,这个函数是__cxa_pure_virtual,自己实现一份

extern "C"
void __cxa_pure_virtual () {
  std::cout<<"In My Pure Virtual Call!"<<std::endl;
}

执行结果是:

In My Pure Virtual Call!
In My Pure Virtual Call!
...

用gdb加个断点,看backtrace就搞定了。

Share

欧冠奖杯展!

    上个周末,欧冠奖杯的全球巡回展来到上海(据说还是亚洲的唯一一站?),那肯定是不容错过的了。
    现场有最近几届欧冠决赛的介绍,大幅照片、比赛用球、签名球衣、奖牌实物,当然,最重要的,欧冠的奖杯!难得有机会这么近距离接触这个大耳朵杯啊,哈哈~
    除此之外还有前著名球星古力特、罗纳德·德波尔的签名,有AC米兰球迷说,他只要古力特的签名,我表示完全理解——因为我甚至都不想要古力特的签名。。。
    有图有真相。


99年俺们家~


08年俺们家~


Mine近距离(可惜不能零距离。。。)接触大耳朵杯

Share

踏青觉岭古道-虹关

    最近有些杂事忙得很,当Daisy召集小型的踏青活动时,第一时间报名了——一定要出去走走换换风景。
    觉岭古道位于江西婺源县北部,靠近安徽,知名度不大,因此游客不多,很适合我们这样的旅游风格。出去玩的人员组成大约是1/3的学友会成员,2/3徒步天涯的驴友以及朋友,因此有很多人都是第一次认识。

    周六晚上出发,一路聊天+自我介绍。特别有意思的是自我介绍环节,从司机后面的开始,每人说一个自己的爱好及名字,后面的人必须接上前面所有人的爱好和名字。比如这回Daisy先说“我是坐司机后面的喜欢睡觉的Daisy”,后面的Lily说“我是坐司机后面的喜欢睡觉的Daisy后面的喜欢吃东西的Lily”,以此类推,当最后一个人介绍时,得记得前面十几个人的爱好和名字以及位置,相当有挑战性!好在我们都喜欢睡觉,因此大多数人的爱好就都是“喜欢睡觉”了,哈哈。
    凌晨3点多到了官坑,住在农家,睡一觉,准备徒步~


    从官坑到岭脚,6.5km左右的山间小道,都是青石板路,很轻松的徒步。这个季节算是繁花似锦吧,除了金灿灿的油菜花,还有粉色的桃花,白色的梨花,白中带点紫的萝卜花,还有不认识的野花,一路都跟着我们的小溪,纯粹的乡土气息。
    找到一片溪边的草坪,大家度地而坐休息看风景吃东西,好不惬意。

    快到岭脚的时候,从山上俯看,一片平房点缀在青山中,很美的画面。

    边走边休息,最后走了3个小时休息了3个小时,从官坑到达了岭脚。
    从岭脚很快就到了虹关,这里有一棵古老的大樟树,宽广的树枝覆盖了一片阴凉,几乎可以和榕树媲美了。一帮人在树下喝茶,吃晚饭,玩牌,真是腐败,哈哈。这回还学了四川的“干瞪眼”的玩法,很有意思!

    虹关村的风景也不错,各种花,还有白菜、竹笋、艾草、马兰头等各种“食材”…

    在虹关的“詹大有饭店”睡到自然醒,这里的老板推荐说附近的有座桥很值得一看,还借了我一辆自行车骑过去,顺道着,老板的狗狗也跟着我一起过去了。这座石桥很有年代感,还是庆元年间建的(庆元已卯年,查了一下,1195年),800多年历史了!可惜老板只有一辆自行车,要不然就喊着大家一起过去看看了。

    在虹关休整完,拍完集体照,准备回上海。不过路上经过黄山屯溪,在屯溪吃个饭,逛一下老街,再悠闲地回到了魔都~

Share