Pregunta

#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;
}

above is a test sample. I find if I use swap(array[1], array[4]);, it also swaps the values of two positions in array. But this confuses me, because the function swap() needs two pointers, not two integer values.

Thanks for your help:)

¿Fue útil?

Solución

using namespace std;  

This is your culprit. When you import the std:: namespace, you get every identifier declared in that namespace, potentially including std::swap.

Thus you are invoking std::swap<int>(int&,int&) (from the standard library) and not ::swap(int*,int*) (from your program.)

The moral of the story: never say using namespace std;. It's just too big.

Otros consejos

It doesn't use your swap, but std::swap.

Try calling it as ::swap(array[1], array[4]); and you'll get an error.

This is why using namespace std; is bad.

This is why you should avoid using namespace std;.

Including a standard header has apparently dragged a declaration of std::swap into your program; and using namespace std; has dumped it into the global namespace. So your code is calling that, not your version.

Would you provide another answer to solve this problem with no temporary variable?

I don't think it can be done. Where does the requirement "no temporary variable" come from, anyway? Do you think temporary variables make your code slower? Let us examine if this is the case here.

Exhibit A: Some hack. Not immediately obvious how it works. Cannot swap a variable with itself correctly:

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

Generated assembly code:

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

Exhibit B: Straight-forward code with a temporary variable. It can swap a variable with itself correctly:

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

Generated assembly code:

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

The temporary variable solution is easier to understand, handles all cases and results in faster code.

Again, outside of interview situations, the xor trick is completely useless. And if I were the interviewer and the candidate knew the xor trick but did not qualify it by saying "This is a cute trick, but I would never use this in the real world", I sure as hell wouldn't hire him. Let me finish this answer with a quote:

Clarity trumps cleverness every time. Larry Osterman

Your problem has nothing to do with using namespace std;. The problem is that you're passing an lvalue reference to an int (int&) to a function that's overloaded on int& and int*. If you removed the using directive, you would not be calling your own swap; in fact, your code wouldn't compile, since C++ does not allow implicit conversion from pointers to int. In order to use your function, you would have to call it as swap(&array[1], &array[4]);

Now, if you corrected your function call to reflect this, it should work, regardless of the presence of the using directive. I would, however, advise against doing so; the semantics of std::swap are to swap two references, not pointers. Not only is overloading standard functions with incompatible semantics confusing to those familiar with the standard library, it may very well break perfectly valid code that uses std::swap on int*.

You may be thinking, "But that will only happen if they're using namespace std;, which they should never do." Believe it or not, however, swap is exactly the sort of application where you do want that using directive (properly scoped, of course). The reason for this is that user code may do exactly what you're trying to do: specialize the swap algorithm. If some library code simply said std::swap, any user-defined overload would be ignored, making that overload useless. If, instead, your code looked like

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

the compiler would be able to employ ADL correctly and choose user-defined swap for any given T (say, int), while still being able to use std::swap for other T.

In other words: always give swap reference parameters, and use a scoped using declaration whenever you need to swap templated types.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top