6
#include <iostream>

using namespace std;

void swap(int *a, int *b) {
    *a = *a^*b;
    *b = *a^*b;
    *a = *a^*b;
}

int main()
{
    int array[]={1,9,2,8,3,7};
    for(int i=0; i<6; i++)
        cout<<array[i];
    cout<<endl;
    swap(array[1], array[4]);
    for(int i=0; i<6;i++)
        cout<<array[i];
    cout<<endl;
    return 0;
}

上面是一个测试样本。我发现如果我使用swap(array[1], array[4]);,它还会交换数组中两个位置的值。但这让我很困惑,因为该函数swap()需要两个指针,而不是两个整数值。

谢谢你的帮助:)

4

5 回答 5

16
using namespace std;  

这是你的罪魁祸首。当您导入std::命名空间时,您会获得在该命名空间中声明的每个标识符,可能包括std::swap.

std::swap<int>(int&,int&)因此,您正在(从标准库)而不是::swap(int*,int*)(从您的程序)调用。

故事的寓意:永远不要说using namespace std;。它太大了。

于 2013-01-24T19:43:49.387 回答
7

它不使用你的 swap,但是std::swap

尝试调用它::swap(array[1], array[4]);,你会得到一个错误。

这就是为什么using namespace std;不好。

于 2013-01-24T19:43:26.553 回答
5

这就是为什么你应该避免using namespace std;

包含一个标准标题显然将声明std::swap拖入您的程序;并将using namespace std;其转储到全局命名空间中。所以你的代码在调用它,而不是你的版本。

于 2013-01-24T19:44:44.223 回答
5

你会提供另一个答案来解决这个没有临时变量的问题吗?

我不认为它可以做到。无论如何,“无临时变量”的要求从何而来?你认为临时变量会让你的代码变慢吗?让我们检查一下这里是否是这种情况。

展览 A:一些 hack。不是很明显它是如何工作的。无法正确地与自身交换变量:

void swap1(int* a, int* b)
{
    *a = *a ^ *b;
    *b = *a ^ *b;
    *a = *a ^ *b;
}

生成的汇编代码:

movl    (%rsi), %eax
xorl    (%rdi), %eax
movl    %eax, (%rdi)
xorl    (%rsi), %eax
movl    %eax, (%rsi)
xorl    %eax, (%rdi)

图表 B:带有临时变量的直截了当的代码。它可以正确地与自身交换变量:

void swap2(int* a, int* b)
{
    int c = *a;
    *a = *b;
    *b = c;
}

生成的汇编代码:

movl    (%rdi), %eax
movl    (%rsi), %edx
movl    %edx, (%rdi)
movl    %eax, (%rsi)

临时变量解决方案更容易理解,可以处理所有情况产生更快的代码。

同样,在面试情况之外,异或技巧完全没用。如果我是面试官,而候选人知道 xor 技巧,但没有通过说“这是一个可爱的技巧,但我永远不会在现实世界中使用它”来限定它,我肯定不会雇用他。让我用一句话来结束这个答案:

清晰总是胜过聪明。拉里·奥斯特曼

于 2013-01-27T08:44:48.120 回答
-1

你的问题与using namespace std;. 问题是您将对 int ( ) 的左值引用传递给在andint&上重载的函数。如果你删除了 using 指令,你就不会调用你自己的交换;事实上,您的代码不会编译,因为 C++ 不允许从指针到 int 的隐式转换。为了使用您的功能,您必须将其称为int&int*swap(&array[1], &array[4]);

现在,如果您更正了函数调用以反映这一点,那么无论使用指令是否存在,它都应该可以工作。但是,我建议不要这样做;的语义std::swap是交换两个引用,而不是指针。重载具有不兼容语义的标准函数不仅会使熟悉标准库的人感到困惑,而且很可能会破坏使用std::swapon 的完全有效的代码int*

您可能会想,“但只有在他们这样做时才会发生这种情况using namespace std;,他们绝不应该这样做。” 然而,信不信由你,swap这正是想要使用指令的那种应用程序(当然,适当的范围)。这样做的原因是用户代码可能会做你想做的事:专门化算法。如果某些库代码简单地说,任何用户定义的重载都将被忽略,从而使该重载无用。相反,如果您的代码看起来像swapstd::swap

template <typename T>
void foo (T& a, T& b)
{
    using std::swap; // Or simply namespace std;
    // ...
    swap (a, b);
    // ...
}

编译器将能够正确使用 ADL 并为任何给定的 T(例如int)选择用户定义的交换,同时仍然能够std::swap用于其他 T。

换句话说:始终提供swap引用参数,并在需要交换模板类型时使用作用域 using 声明。

于 2013-01-25T03:56:22.383 回答