为什么 swap() 在我不用两个指针调用它时可以很好地工作?

why swap() can work well when I don't call it with two pointer?

本文关键字:工作 调用 很好 两个 swap 为什么 指针      更新时间:2023-10-16
#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()需要两个指针,而不是两个整数值。

感谢您的帮助:)

using namespace std;  

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

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

故事的寓意:永远不要说using namespace std; .实在是太大了。

它不使用您的swap,但std::swap

尝试将其称为 ::swap(array[1], array[4]);,您将收到错误。

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

这就是为什么

你应该避免using namespace std;

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

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

我认为这是做不到的。"无临时变量"的要求到底从何而来?你认为临时变量会让你的代码变慢吗?让我们检查一下这里是否是这种情况。

图表A:一些黑客。它是如何工作的不是很明显。无法正确交换变量:

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)

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

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

每次都胜过聪明。拉里·奥斯特曼

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

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

你可能会想,"但这只有在他们using namespace std;的情况下才会发生,他们永远不应该这样做。然而,信不信由你,swap正是你想要使用指令的应用程序(当然,范围正确)。这样做的原因是用户代码可能完全按照您正在尝试做的事情:专门化swap算法。如果某些库代码只是简单地说std::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引用参数,并在需要交换模板化类型时使用作用域内声明。

相关文章: