Skip to main content
added 1910 characters in body
Source Link
Loki Astari
  • 97.7k
  • 5
  • 126
  • 341

Note on the use of const.

If you put const on the right or left is a style thing. Peronally I always put it on the right. As there are a couple of corner cases (with typedef) were it does make a difference and I want to be consistent.

Note: cost always binds to the type on its left. unless it is the left-most part of a type declaration then it binds right. Read type right to left.

char const*       str1;  // const binds left to char  => (char const)*
                         // Read as: pointer to 'const char'

char const *const str2;  // const binds left => (char const) (* const)
                         // Read as: 'const pointer' to 'const char'

// From the C world (and it has leaked into C++) so a lot of people still us it
const char*       str3;  // const as left-most part binds right => (const char) *
                         // Read as: pointer to 'char const'

Basically str1 and str3 are identical. But the consistency of always thinking that const binds to the left makes it neater in my mind.

One place where it can make a difference is typedefs. This is because the typedef has already formed a type so any external const are applied to the typedef type as a whole thing (not as individual parts).

typedef char* String;
const String   str4;     // const is the left-most item so binds right.
                         // So you may expect this to be the same as str3

                         // unfortunately this is not correct as the typedef
                         // String a whole type so the const applies to `String`
                         // not to the char.

                         // Thus this is like const (char*)
                         // Which is the same as (char*) const
                         // Read: const 'pointer to char' so once set the pointer
                         // can not be moved.
 // If on the other hand you never put const in the left-most position then
 // this problem never even comes up.

So two reasons not to put const as the left-most part of the type.

Note on the use of const.

If you put const on the right or left is a style thing. Peronally I always put it on the right. As there are a couple of corner cases (with typedef) were it does make a difference and I want to be consistent.

Note: cost always binds to the type on its left. unless it is the left-most part of a type declaration then it binds right. Read type right to left.

char const*       str1;  // const binds left to char  => (char const)*
                         // Read as: pointer to 'const char'

char const *const str2;  // const binds left => (char const) (* const)
                         // Read as: 'const pointer' to 'const char'

// From the C world (and it has leaked into C++) so a lot of people still us it
const char*       str3;  // const as left-most part binds right => (const char) *
                         // Read as: pointer to 'char const'

Basically str1 and str3 are identical. But the consistency of always thinking that const binds to the left makes it neater in my mind.

One place where it can make a difference is typedefs. This is because the typedef has already formed a type so any external const are applied to the typedef type as a whole thing (not as individual parts).

typedef char* String;
const String   str4;     // const is the left-most item so binds right.
                         // So you may expect this to be the same as str3

                         // unfortunately this is not correct as the typedef
                         // String a whole type so the const applies to `String`
                         // not to the char.

                         // Thus this is like const (char*)
                         // Which is the same as (char*) const
                         // Read: const 'pointer to char' so once set the pointer
                         // can not be moved.
 // If on the other hand you never put const in the left-most position then
 // this problem never even comes up.

So two reasons not to put const as the left-most part of the type.

added 1910 characters in body
Source Link
Loki Astari
  • 97.7k
  • 5
  • 126
  • 341

What about:

std::cout << ::strlen("Plop Poop") << "\n";

While we are at it:

// use std::size_t to represent a size of something in memory
// It is non negative and is explicitly designed so it can represent
// the biggest in memory object.
//
// Pass C-String as 'char const*' (or const char* (samething))
// The compiler will automatically add a const to objects if required.
// BUT it will never remove a const (apart from 1 special case see below).
// Also the type of a string literal is 'char const*` (for the language lawyers yes it is an array but not relevant here as by the time we will see it is a pointer).
//
// Also, because you don't want to mutate the underlying string it gives
// you some slight protection from accidental assignment into the string.
std::size_t martinStringLen(char const* start)
{
    char const* end = start;

    // Look for the end of the string.
    // Your code increments two objects. I would just increment a single object
    // looking for the end of the string.
    for(;*end;++end){/*Empty*/}

    // The size is then just subtraction.
    return end - start;
}

// Unfortunately the special case is string literals: which is allowed to decay
// to char* for compatibility with old C code.

Other notes on your code:

int cpl(char * c)       // does work
int cpl(const char * c) // converts to char* so it can do work.

You have these two the wrong way around.
Make the int cpl(const char * c) version do the work. As noted above you are not mutating the object so it provides some slight protection from simple mistakes.

Also you will find the int cpl(char * c) version becomes unnecessary. As the compiler will automatically add const (ness) to parameters for you so you don't actually need the this version.

Other comments are same as @Konrad Rudolph

What about:

std::cout << ::strlen("Plop Poop") << "\n";

What about:

std::cout << ::strlen("Plop Poop") << "\n";

While we are at it:

// use std::size_t to represent a size of something in memory
// It is non negative and is explicitly designed so it can represent
// the biggest in memory object.
//
// Pass C-String as 'char const*' (or const char* (samething))
// The compiler will automatically add a const to objects if required.
// BUT it will never remove a const (apart from 1 special case see below).
// Also the type of a string literal is 'char const*` (for the language lawyers yes it is an array but not relevant here as by the time we will see it is a pointer).
//
// Also, because you don't want to mutate the underlying string it gives
// you some slight protection from accidental assignment into the string.
std::size_t martinStringLen(char const* start)
{
    char const* end = start;

    // Look for the end of the string.
    // Your code increments two objects. I would just increment a single object
    // looking for the end of the string.
    for(;*end;++end){/*Empty*/}

    // The size is then just subtraction.
    return end - start;
}

// Unfortunately the special case is string literals: which is allowed to decay
// to char* for compatibility with old C code.

Other notes on your code:

int cpl(char * c)       // does work
int cpl(const char * c) // converts to char* so it can do work.

You have these two the wrong way around.
Make the int cpl(const char * c) version do the work. As noted above you are not mutating the object so it provides some slight protection from simple mistakes.

Also you will find the int cpl(char * c) version becomes unnecessary. As the compiler will automatically add const (ness) to parameters for you so you don't actually need the this version.

Other comments are same as @Konrad Rudolph

Source Link
Loki Astari
  • 97.7k
  • 5
  • 126
  • 341

What about:

std::cout << ::strlen("Plop Poop") << "\n";