比较变量地址并不可靠

Haoxiang Li bio photo By Haoxiang Li

最近云风大牛又在黑我C++,可是在我学会之前,我还是要坚定不移地待在这贼船上。 嘿嘿 :]

“用比较地址的方法来判断两个变量(的引用)是不是同一个变量是不可靠的”,这个问题很简单,却也容易忽视。

现实的情况是这样的。在写Computer Vision实验的时候,因为程序要面临的计算量往往很大,对程序的性能的优化是十分重要的。 所以我就写出了这样的代码:

void foo_func(Foo& foo)
{
    //< 如果foo和上次传入的是同一个,就省掉一部分重复计算
    static Foo *p_foo = NULL;
    if (p_foo != &foo)
    {
        p_foo = &foo;
        //< 大量计算
    }

    //< 后续计算
}

在实验里,Foo这个类本身往往比较复杂,不可能做内容的逐一比较,同时这个类的实例在初始化之后内容就保持不变。写这个函数的时候没有觉得有什么问题,结果也是正确的。

但是,这么做显然是不可靠的。 这段代码就说明问题了:

#include 

int main(int argc, char **argv)
{
    using namespace std;
    for (int i = 0; i < 100; i++)
    {   
        int j;
        cout << "i: " << i << " &j: " << &j << endl;
    }   
    return 0;
}
</pre>

在Mac下输出是这样的:
i: 0 &j: 0x7fff52decad0
i: 1 &j: 0x7fff52decad0
i: 2 &j: 0x7fff52decad0
i: 3 &j: 0x7fff52decad0
i: 4 &j: 0x7fff52decad0
i: 5 &j: 0x7fff52decad0
i: 6 &j: 0x7fff52decad0
i: 7 &j: 0x7fff52decad0
i: 8 &j: 0x7fff52decad0
i: 9 &j: 0x7fff52decad0
....
编译器在分配内存的时候,会去复用之前刚刚释放掉的空间,这个是很显然的道理。在上面这种循环里面,局部变量所在的那块空间正好一直被同一个变量复用,如果我每次给j初始化不同的值,它们的地址一致但却不是同一个变量,所以像这样比较变量地址并不可靠。 现在看来,一个可能的解决方法就是给Foo的每一个实例增加一个唯一的ID了。 有没有不用修改Foo就能达到快速比较两个Foo实例的方法呢?