3

Many times I write C++ functions I seem to use many more const modifiers than other folks.

For example, I write Excel .xlsx files and I use LibXL library for this, and the documentation mentions a function like this:

bool writeNum(int row, int col, double value, Format* format = 0)

I happened to inherit this function and my signature looks like this:

bool XLAPIENTRY writeNum(const int row, const int col, const double value, IFormatT<wchar_t> * format = 0);

Note the const ints for the row and the column.

Question: is it safe to leave out const for ints? (It's obviuos that for pointers, leaving out const for pointers is dangerous, but doing something a local copy of an int is not that dangerous). Note that the original header containing writeNum function doesn't mention const-ing the ints, too. Why is here the const modifiers left out?

Sebastian
  • 1,834
  • 2
  • 10
  • 22
Gyula Sámuel Karli
  • 3,118
  • 2
  • 15
  • 18
  • 1
    It's safe to leave out `const` for ints (and doubles) – john Oct 17 '22 at 08:55
  • See also [this discussion](/questions/117293/use-of-const-for-function-parameters) which now would have been closed because of "asking for opinions". – Botje Oct 17 '22 at 08:56
  • 3
    Note that `const int* ptr` and `int* const ptr` are two different declarations. In the first the `int` is constant, in the second the pointer is constant. In the second case it's also safe to leave out the `const`, just as with ints. – john Oct 17 '22 at 08:56
  • Using `const` has several related purposes here, which are not clearly annotated separately in C++. 1) It is a contract with the caller. This is only important for references and pointers (with `const` before the `*`), not for non-pointer parameters by value. 2) The parameters act like local variables in the called function. Using `const` would actually be an implementation detail, which has leaked into the function signature. This is relevant for non-pointer value parameters and pointers with `*` before `const`. 3) The `const` can also be a performance hint for the optimizer. – Sebastian Oct 17 '22 at 09:10
  • In your case, 1) does not apply for the `int`s - they are value parameters. 3) The `int`s can be copied without effort, they are typically smaller than a 64-bit-pointer, so internally using a const reference (which would be a possible optimization for larger objects) would be slower. So only 2) remains, which is an implementation detail of your function. There were ideas (and proposals) to now treat the signature of const value parameters like non-const value parameters, but those will probably go nowhere to keep backwards compatibility. – Sebastian Oct 17 '22 at 09:25
  • @john The same goes with `int const v`. It's actually a specific rule in the standard that makes `const Type thing` and `Type const thing` equivalent - and that rule doesn't apply to your first sample. – Peter Oct 17 '22 at 09:58

1 Answers1

8

In declaration (as opposed to definition), the top-level1 const on a parameter has no effect. Arguably, it's an implementation detail of the function, that shouldn't appear in the declaration (it adds clutter, yet doesn't provide any new information for the caller).

Note that const int x and int *const x are top-level const, while const int * and const int & are not, so the latter can't have its const removed.

In definition, you can include the const if it helps you as the implementer of the function (so you don't change the parameter accidentally).


1 "Top-level const" means "actually const", as opposed to e.g. merely being a pointer to const. You can check this property with std::is_const_v.

E.g.:

  • std::is_const_v<const int> == true (const integer)
  • std::is_const_v<const int *> == false (non-const pointer to const integer)
  • std::is_const_v<int *const> == true (const pointer to non-const integer)
  • std::is_const_v<const int **> == false (non-const pointer to non-const pointer to const integer)
  • std::is_const_v<int *const *> == false (non-const pointer to const pointer to non-const integer)
  • std::is_const_v<int **const> == true (const pointer to non-const pointer to non-const integer)
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • Huh. As far as I understand top-level const is a const pointer, while low level const is a constant value. 1. Is it right? 2. If so, why "const in x" is a top-level stuff (if "x" means here the name of the parameter). – Gyula Sámuel Karli Oct 17 '22 at 09:43
  • @GyulaSámuelKarli 1. Yes. 2. For non-pointer types, there's only one "level" of constness, so it can be considered top-level too. Or, for `int **x`, there are three possible places where `const` can be added (3 levels), and only one of them is "top-level" (the `int **const x` one). – HolyBlackCat Oct 17 '22 at 09:44
  • 1
    @GyulaSámuelKarli In general, if `std::is_const_v` returns true, then it's top-level const. `std::is_const_v` is true. – HolyBlackCat Oct 17 '22 at 09:56
  • A naive question, is "top-level" an obvious stuff for somebody in the C++ business? I think this should be added to the answer – Gyula Sámuel Karli Oct 17 '22 at 09:57
  • @GyulaSámuelKarli I was hoping it's going to be obvious, but maybe not. I've added a short explanation. – HolyBlackCat Oct 17 '22 at 10:07
  • That's cool, I really appreciate it. Most manuals about const stuff leave out these details and I now read Bjarne Stroustrup's C++ book and that doesn't go into such depth, too. – Gyula Sámuel Karli Oct 17 '22 at 10:11