1

I'm following simple C++ tutorial.

#include <iostream>
using namespace std;

int main()
{
  int a = 1, b = 2;

  cout << "Before swapping " << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  swap(a,b);

  cout << endl;
  cout << "After swapping " << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  return 0;
}

void swap(int &n1, int &n2)
{
  int temp;
  temp = n1;
  n1 = n2;
  n2 = temp;
}

The above code works fine (both g++ and icc), but if I were to use pointers in the functions the code fails if I do not include the prototype at the head of the program.

#include <iostream>
using namespace std;

void swap(int*, int*);  // The code fails if I comment this line.

int main()
{
  int a = 1, b = 2;

  cout << "Before swapping" << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  swap(&a, &b);

  cout << endl;
  cout << "After swapping" << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  return 0;
}

void swap(int* n1, int* n2)
{
  int temp;

  temp = *n1;
  *n1 = *n2;
  *n2 = temp;
}

As far as I know, C++ compiling process is top-bottom, so the 2nd code seems more reasonable in which the information of the function is provided before int main() is encountered. My question is, why the 1st code works fine even without the knowledge of function before int main()?

Sangjun Lee
  • 406
  • 2
  • 12
  • 6
    See also [Why is “using namespace std;” considered bad practice?](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice) – Miles Budnek Aug 24 '20 at 23:42
  • 3
    If you want another surprise, remove the `swap()` function entirely from the first example. You'll find the code will build and run without it. – Peter Aug 25 '20 at 00:37
  • @MilesBudnek Ah ha! I didn't even imagine that the ```std``` was the cause of the problem. Thank you :) – Sangjun Lee Aug 25 '20 at 01:36

3 Answers3

6

The issue with the first program is you're not actually calling your own swap function. At the top of the file, you have:

using namespace std;

which brings std::swap into scope and that's the function that you're actually calling. If you put a cout statement in your own swap you'll see that it's never actually called. Alternatively, if you declare your swap before main, you'll get an ambiguous call.

Note that this code is not required to behave like this, since iostream doesn't necessarily bring std::swap into scope, in which case you'll get the error that there is no swap to call.

In the second program, the call to swap(&a, &b) fails because there is no overload of std::swap that accepts 2 temporary pointers. If you declare your swap function before the call in main, then it calls your own function.

The real bug in your code is the using namespace std;. Never do that and you'll avoid issues of this nature.

cigien
  • 57,834
  • 11
  • 73
  • 112
  • "which brings std::swap into scope " ... but possibly NOT on every compiler. It is still recommended that when you wish to use std::swap, you should always #include the appropriate header. It is possible that the one include you have also includes swap, but not guaranteed. Just today I see std::swap() is in 3 headers now: (where I expected it), and , and . – 2785528 Aug 25 '20 at 02:24
3

The reason why the first version works is because it doesn't call your swap(...) function at all. The namespace std provides - Edit: depending on the headers you (and the standard headers themselves) include - swap(...) functions for various types and integers are one of them. If you would remove using namespace std you would have to type std::swap(...) to achieve the same effect (same goes for std::cout, std::endl).

That's one reason why using namespace is a double-edged sword for beginners in my opinion but that's another topic.

Paulsor
  • 100
  • 7
  • 1
    "The namespace std provides swap(...) functions ... ". No. std::namespace does NOT provide libraries ... Libraries provide contributions to std::namsepace. std::swap is guaranteed to be provided in specific libraries, but not all the libraries which are contributors to std::namespace will provide std::swap. For instance, cppreference.com reports that std::swap() can be directly fetched from 3 headers: , , and . Depending on tool suite, it might be indirectly included in other libraries. – 2785528 Aug 27 '20 at 21:12
  • @2785528 You're right, I edited my answer to incorporate your hint. – Paulsor Aug 27 '20 at 23:35
0

Your code is fine; but you're right, it fails if you comment on the line you point to. But actually, as the others tell you, there is a Swap function in c ++, so it doesn't matter if you create a prototype of the function and do it later because the compiler calls its own swap function.

But since swap works for any data type, except for pointers, then you will understand the reason for your problem, since in this case you do have to create your own swap function that accepts pointers as parameters.

Just move your function above main to make it work correctly, nothing more:

#include <iostream>
using namespace std;

//void swap(int*, int*);  // The code fails if I comment this line.
void swap(int* n1, int* n2)
{
  int temp;

  temp = *n1;
  *n1 = *n2;
  *n2 = temp;
}

int main()
{
  int a = 1, b = 2;

  cout << "Before swapping" << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  swap(&a, &b);

  cout << endl;
  cout << "After swapping" << endl;
  cout << "a = " << a << endl;
  cout << "b = " << b << endl;

  return 0;
}
  • "because the compiler calls its own swap function." No. The compiler will search only listed include libraries (and the libraries they include, i.e. indirect). std::swap is linked only when a) it is used (referenced) in your code, and b) found in an included library. If, on your build suite, the library does not (directly nor indirectly) contain a std::swap, the compiler gives up, and reports an undefined function. – 2785528 Aug 27 '20 at 21:02