分类: C/C++
2012-12-15 01:22:39
C++是一门神奇的语言,喜欢它的人,非常非常的迷恋它;厌恶它的人,非常非常的憎恨它。我并不想引领什么语言争论,我只是想说它真是一门好语言,但是并不是对应所有人来说的。因为你可以用它做坏事。用它,我们必须给我们自己编一个编程纲领,规定我们什么该做,什么不该做。否则,它就是你的噩梦。
今天一到办公室,我就和一位同事为了一个bug fix争论了起来。让我们先来看看,这是一个什么样的问题:
{code}
class A;
static A *p_a = NULL;
class A {
public:
A() { p_a = this; cout << "A constructor." << endl; sleep(5); }
virtual void test() =0;
};
class B : public A {
public:
B() { cout << "B constructor." << endl; }
void test() { cout << "test B()." << endl; }
};
void* alloc_obj(void* p)
{
p_a = new B;
}
void* access_obj(void* p)
{
p_a->test();
}
int main()
{
pthread_t tid1, tid2;
cout << "start..."<< endl;
pthread_create(&tid1, NULL, alloc_obj, NULL); <===== thread-1
sleep(2);
pthread_create(&tid2, NULL, access_obj, NULL); <===== thread-2pthread_join(tid1, NULL);
pthread_join(tid2, NULL);cout << "main exit" << endl;
return 0;
}
{code}
看出其中的问题了吗?thread-2的执行结果是什么?
我和我同事所要争论的东西其实很简单,就是冲着他提供的fix方案:把test() 改成非纯虚函数,并给它提供一个实现,以绕过这个panic。
但是这里的基本问题是:把一个没有构造好的对象暴露出去,这本身就是一个错误的编程。而给A的test提供一个实现,只是使这种情况更加糟糕。因为这样做肯定违背了当初设计者的想法,就是子类必须提供一个test实现,而不能依赖于这里的(当然,另外一个方案就是保持纯虚函数,但是提供一个实现)。这样做也许可以解决眼前的问题,但是并没有解决这里的最基本的编程错误。也许在将来的某个时候,这种编程会引起更严重的问题。因为外界可以访问一个没有构造好的对象。
这就是编程,很多方案可以解决同一个问题,但是并不是所有人都能看出其中的奥秘,并选中一个最好的,或者说最优的方案。
作为一个C++工作者,我们必须培养这样的能力,去辨别什么才是没有副作用的解决方案,什么技术应该用在什么地方。
大家看看对这个问题有什么想法?一起讨论。