6

I am confused why the following code is not producing any error ,because the arguments passed to display are of same type i.e char.Does const really makes difference?

#include<iostream>

using namespace std;

void display(char *p)
{
    cout<<p;
}
void display(const char *p)
{
    cout<<p;
}

int main()
{
    display("Hello");
    display("World");
}

EDIT As per answers,the first display is never called,which is correct and so is the output.

But suppose I do it like :

int main()
{
    char *p="Hello";
    display(p);//now first display is called.
    display("World");
}

Compiler gives a warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings] but then it calls first display.Does it mean that string is now no more taken as constant?

Naveen
  • 7,944
  • 12
  • 78
  • 165
  • Yes, it does make a difference. One of those overloads should not be viable. – chris Jul 26 '13 at 07:25
  • 1
    The quick answer is "yes, `const` makes a difference." In fact `f(int x)` and `f(int x) const` also makes a difference! – Codie CodeMonkey Jul 26 '13 at 07:25
  • For completeness: top-level-`const` on value parameter doesn't make a difference `f(int x)` and `f(const int x)` are the same. – Henrik Jul 26 '13 at 07:28
  • 1
    The arguments passed are of type `const char[N]`, both of which decay to `const char*`. – juanchopanza Jul 26 '13 at 07:32
  • String literals won't bind to `char*` – Bartek Banachewicz Jul 26 '13 at 07:36
  • Your second code will give you a warning, since the `const` qualifier is discarded in the initialisattion of `*p`. – urzeit Jul 26 '13 at 07:43
  • 1
    @urzeit :Yes it is giving a warning `warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]` but then it calls first `display`.Does it mean that `string` is now no more taken as constant. – Naveen Jul 26 '13 at 07:46
  • 1
    @Insane Coder: Yes. This may lead to terrible errors if you try to modify the data in `*p` and the implementation does not allow so (if the data is in ROM, e.g.) – urzeit Jul 26 '13 at 07:50

6 Answers6

11

const char* and char * are actually not the same. The later allow for modifying the pointed char, while the first one will prevent that.

Also note that if those were class methods, void display() and void display() const would also be valid overloads. The later would imply that the method must not change the object's state.

Consider this code:

void    display(char *s)
{
  std::cout << "Display" << std::endl;
}

void    display(const char *s)
{
  std::cout << "Display with const" << std::endl;
}

int     main()
{
  char  *str = strdup("boap");
  const char *str2 = "toto";
  /* It is a string literral "bound" as a char *.                                                                               
     Compiler will issue warning, but it still compiles.                                                                        
     Avoid to do that, it's just an exemple */
  char  *not_safe = "not_safe";

  display("llama");
  display(str2);
  display(str);
  display(not_safe);
}

This will print Display with const twice, and then twice Display. See there. Now, let's see why:

  • "llama" is a string literal, and then is resolved as a const char *.
  • str2 is a pointer to a string literal. Since its type is const char*, this also revolves to the const overload.
  • not_safe is also a pointer to a string literal. However, its type is char *: this is not correct. The memory it points to is read-only, and trying to modifies it will result in a crash. However, the type of the variable is still char *, so this resolve to the non-const overload.
  • str is a char * pointer, and the string it points to is not read-only. Modifying its content is valid, and since its type is char *, it will resolve to the non-const overload.
Xaqq
  • 4,308
  • 2
  • 25
  • 38
3

The issue is that string literals such as "Hello" and "World" have type const char[6]. This can decay to const char*, but not to char*. So the overload taking const char*,

 void display(const char *p);

is the better match. As @JamesKanze points out, it would be possible for a function taking char* to accept a string literal, but attempting to modify the data pointed at would result in undefined behaviour. For this reason, it is unsafe to pass string literals to such functions. With suitable warning settings, GCC produces the following:

warning: deprecated conversion from string constant to ‘char*’

In any case, in the presence of two overloads like the ones you have shown, the one taking const char* wins.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • The resulting `char const*` _will_ convert implicitly to `char*`, if there are no other overloads. (For historical reasons only, of course. One shouldn't use this feature in new code.) – James Kanze Jul 26 '13 at 07:56
0

The arguments passed to the two functions are actually not the same.

The first takes a char*: A pointer to a char.

The second takes a const char*: A pointer to a const char.

So you see, the difference here is actually in whether the pointer points to an object which can be changed or not. This is definitely a property on which you want to be able to overload a function.

Agentlien
  • 4,996
  • 1
  • 16
  • 27
0

Whether you can modify an object or not definitely is a useful piece of information depending on which you may want to invoke different behavior! Consider this:

void foo(int * p) { ++(*p); }
void foo(int const * p) { std::cout << *p << '\n'; }
nikolas
  • 8,707
  • 9
  • 50
  • 70
0

The sizes of the strings "Hello" and "World" are known at compile time and cannot be modified. They are constant, compile-time character arrays.

In C and C++, an array e.g. char a[6] can be referred to using a pointer, i.e. a is actually a char *. Since the arrays for "Hello" and "World" must not be modified at runtime, their type is essentially const char *.

The compiler recognizes this and performs the overload resolution for display correctly, since only one of the functions (display(const char* p)) takes a const char* as an argument. This is why there is no ambiguity in the two functions, and you don't get the error that you expected to get.

maditya
  • 8,626
  • 2
  • 28
  • 28
  • The statement "`a` is actually a `char*` is false. There is an implicit conversion, which takes place in a number of contexts, but the types are still distinct (and there are contexts where the conversion doesn't occur). – James Kanze Jul 26 '13 at 07:58
0

"because the arguments passed to display are of same type i.e char."

No here the argument are "const char*". the data type is the but the const qualifier indicate that the literal string you hard coded, is not something that can be change.

"Does const really makes difference?"

Yes the const qualifier make a difference. in Display(char*) you can update the content of the null-terminate string you passed but not in Display(const char*). That fact allow more optimization by the compiler.

But read that http://www.possibility.com/Cpp/const.html it's a good source to start using const efficiently.

alexbuisson
  • 7,699
  • 3
  • 31
  • 44