最近云风大牛又在黑我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实例的方法呢?
所以你看还是所有东西继承自Object比较好,有个GetHash()函数就什么都解决了。。
也是啊…可以自己实现一个hash来比较,但是如果object很大,GetHash也要好些时间吧
万能的方法是肯定不存在的,针对自己特定的问题的话,用有代表性的域去计算hash会比较好吧。另外,比较指针来判断是否是同一个object的话,一般是在两个object都确保没有释放的前提下,而且如果内部某些域可能被改变的话,也要去比较那些域的指针才能确保。
嗯,一定要确保object没有被释放。所以经过讨论之后,一个可以的做法是用一个shared_ptr把每次传进来的那个Object hold住,这样每次比较地址的时候就是两个活着的Object在比较了。或者,我觉得也可以用一个weak_ptr指向上次传进来的那个Object,这样就可以知道上次那个Object是不是被释放了。
新年好! :]
我也觉得如果这个对象过于复杂,通过组合了不同的功能,还是给一个唯一的id识别比较好,安全又简单。