почему swap () может хорошо работать, когда я не вызываю его с двумя указателями?

#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() нужны два указателя, а не два целочисленных значения.

Спасибо за вашу помощь:)

6

Решение

using namespace std;

Это твой виновник. Когда вы импортируете std:: пространство имен, вы получаете каждый идентификатор, объявленный в этом пространстве имен, в том числе std::swap,

Таким образом, вы призываете std::swap<int>(int&,int&) (из стандартной библиотеки) а не ::swap(int*,int*) (из вашей программы.)

Мораль этой истории: никогда не говори using namespace std;, Это просто слишком большой.

16

Другие решения

Не использует ваш swap, но std::swap,

Попробуйте назвать это как ::swap(array[1], array[4]); и вы получите ошибку.

Вот почему using namespace std; плохо.

7

Вот почему вы должны избегать using namespace std;,

Включение стандартного заголовка, по-видимому, затянуло декларацию std::swap в вашу программу; а также using namespace std; сбросил его в глобальное пространство имен. Так ваш код называет это, а не ваша версия.

5

Не могли бы вы дать другой ответ для решения этой проблемы без временной переменной?

Я не думаю, что это может быть сделано. В любом случае, откуда берется требование «нет временной переменной»? Как вы думаете, временные переменные замедляют ваш код? Давайте посмотрим, так ли это здесь.

Приложение А: Немного взломать. Не сразу понятно, как это работает. Невозможно правильно поменять местами переменную:

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 совершенно бесполезна. И если бы я был интервьюером, и кандидат знал ход трюка, но сделал не уточните это, сказав: «Это милый трюк, но я бы никогда не использовал его в реальном мире», я уверен, что, черт возьми, он его не наймет. Позвольте мне закончить этот ответ цитатой:

Ясность превосходит ум каждый раз. Ларри Остерман

5

Ваша проблема не имеет ничего общего с using namespace std;, Проблема в том, что вы передаете ссылку lvalue в int (int&) к функции, которая перегружена int& а также int*, Если вы удалите директиву using, вы не будете вызывать собственный своп; на самом деле ваш код не будет компилироваться, поскольку C ++ не позволяет неявное преобразование из указателей в int. Для того, чтобы использовать вашу функцию, вы должны вызвать ее как swap(&array[1], &array[4]);

Теперь, если вы исправили свой вызов функции, чтобы отразить это, он должен работать, независимо от наличия директивы using. Однако я бы посоветовал не делать этого; семантика std::swap должны поменяться двумя Рекомендации, не указатели. Мало того, что перегрузка стандартных функций несовместимой семантикой сбивает с толку тех, кто знаком со стандартной библиотекой, она вполне может нарушить совершенно корректный код, который использует std::swap на int*,

Вы можете подумать: «Но это произойдет, только если они 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 для других Т.

Другими словами: всегда дать swap ссылаться на параметры и использовать декларацию с использованием области видимости, когда вам нужно поменять шаблонные типы.

-1