in Blog Posts, C/C++, Computer Vision (机器视觉), Solution

比较变量地址并不可靠

最近云风大牛又在黑我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;
}

在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实例的方法呢?

Write a Comment

Comment

  1. 万能的方法是肯定不存在的,针对自己特定的问题的话,用有代表性的域去计算hash会比较好吧。另外,比较指针来判断是否是同一个object的话,一般是在两个object都确保没有释放的前提下,而且如果内部某些域可能被改变的话,也要去比较那些域的指针才能确保。

    • 嗯,一定要确保object没有被释放。所以经过讨论之后,一个可以的做法是用一个shared_ptr把每次传进来的那个Object hold住,这样每次比较地址的时候就是两个活着的Object在比较了。或者,我觉得也可以用一个weak_ptr指向上次传进来的那个Object,这样就可以知道上次那个Object是不是被释放了。

      新年好! :]

  2. 我也觉得如果这个对象过于复杂,通过组合了不同的功能,还是给一个唯一的id识别比较好,安全又简单。