这是在解JOJ 1170题目的时候遇到的问题,使用replace函数得不到期望结果,调试发现replace函数没有正确执行,查看STL中的源代码发现了问题。针对这个问题重新写一小段测试代码:
- #include <algorithm>
- #include <cstdio>
- #include <ctime>
- #include <cstdlib>
- using namespace std;
- int main() {
- int testArr[16], i;
- srand(time(0));
- for(i = 0; i < 16; i++)
- testArr[i] = rand() % 5;
- printf("before replace:/n");
- for(i = 0; i < 16; i++)
- printf("%3d", testArr[i]);
- printf("/n");
- printf("after replace testArr[0] with testArr[1]:/n");
- replace(testArr, testArr+16, testArr[0], testArr[1]);
- for(i = 0; i < 16; i++)
- printf("%3d", testArr[i]);
- printf("/n");
- printf("helo world");
- return 0;
- }
-
输出结果如下:
before replace:
2 1 1 4 4 3 2 2 0 3 1 4 0 3 2 0
after replace testArr[0] with testArr[1]:
1 1 1 4 4 3 2 2 0 3 1 4 0 3 2 0
根据程序的期望,执行后应该把原数组中的所有的2都替换成1,但输出结果却表示程序仅仅把第一个2替换成了1,后面的2都还是保持不变的。
用的编程环境是Emacs+MinGW,用gdb调试执行到replace调用处,输入s命令跟踪到replace的源代码,如下:
这段代码在stl_algo.h头文件中:
- template<typename _ForwardIter, typename _Tp>
- void
- replace(_ForwardIter __first, _ForwardIter __last,
- const _Tp& __old_value, const _Tp& __new_value)
- {
-
- __glibcpp_function_requires(_Mutable_ForwardIteratorConcept<_ForwardIter>)
- __glibcpp_function_requires(_EqualOpConcept<
- typename iterator_traits<_ForwardIter>::value_type, _Tp>)
- __glibcpp_function_requires(_ConvertibleConcept<_Tp,
- typename iterator_traits<_ForwardIter>::value_type>)
- for ( ; __first != __last; ++__first)
- if (*__first == __old_value)
- *__first = __new_value;
- }
执行到这里,还是看不出来问题,单步执行并用disp命令查看__old_value和__new_value的时候才发现,在第一次替换操作执行之后,__old_value竟然变成了__new_value,所以后面就不会再进行任何替换操作了。
出现问题的原因是什么呢?显然是因为replace函数后两个参数是const T&型的,当使用
replace(testArr, testArr+16, testArr[0], testArr[1]);
来调用时,传进去的不是testArr[0]的值,而竟然是testArr[0]的地址!!!
把上述调用修改成:
replace(testArr, testArr+16,(int) testArr[0],(int) testArr[1]);
这样调用才不会出现问题。
同样的代码在VC6.0中也是同样的问题。而且在online judge上也是这样。按照以前的那种调用写法,提交上去得了个wrong answer,写成后一种调用,就accepted了。