I was looking for examples on how to do something and saw this two variants:
std::string const &s;
const std::string &s;
in different snippets.
thx for your answer :)
std::string is the string class from the standard C++ library. String is some other string class from some other library. It's hard to say from which library, because there are many different libraries that have their own class called String.
The data type const string& literally means “a reference to a string object whose contents will not be changed.” There are three ways to pass things around (into and out of functions) in C++: Pass by value - a copy of the original object is created and passed.
string is an object meant to hold textual data (a string), and char* is a pointer to a block of memory that is meant to hold textual data (a string). A string "knows" its length, but a char* is just a pointer (to an array of characters) -- it has no length information.
String constants, also known as string literals, are a special type of constants which store fixed sequences of characters. A string literal is a sequence of any number of characters surrounded by double quotes: "This is a string." The null string, or empty string, is written like "" .
std::string const &
is equivalent to const std::string &
.
const std::string &
is the style adopted in Stroustrup's The C++ Programming Language and probably is "the traditional style".
std::string const &
can be more consistent than the alternative:
the const-on-the-right style always puts the
const
on the right of what it constifies, whereas the other style sometimes puts theconst
on the left and sometimes on the right.With the const-on-the-right style, a local variable that is const is defined with the const on the right:
int const a = 42;
. Similarly a static variable that is const is defined asstatic double const x = 3.14;
. Basically everyconst
ends up on the right of the thing it constifies, including theconst
that is required to be on the right: with a const member function.
(see What do “X const& x” and “X const* p” mean? for further details).
If you decide to use const-on-the-right style, make sure to don't mis-type std::string const &s
as the nonsensical std::string & const s
:
The above declaration means: "s
is a const
reference to a std::string
".
It's redundant since references are always const
(you can never reset a reference to make it refer to a different object).
Technically it is the same and does not make any difference. But in some debuggers (lldb for sure) you will see std::string const&
even if you have written as const std::string&
.
As noted, they're the same type. One reason to like the const
on the right is how it plays with templates. Most people process function templates by just substitution. For example:
template <class T> void foo(const T& arg);
int* p;
foo(p);
What is the type of arg
? You want to say const int*&
, which is to say, a reference to a pointer to const int
, but that is wrong. Text substitution has failed you. If you has written it instead like
template <class T> void foo(T const& arg);
Then simple text substitution yields the correct type: int* const&
. That is, a reference to const
pointer to int
.
As Barry noted in his answer the old C syntax (and the C++ extension of that syntax) doesn't support the conceptual view of text substitution, as in mathematics.
Using the C syntax directly it's therefore generally a good idea to write T const
, not const T
, even though when T
is a simple type these type expressions are equivalent. Writing T const
also avoids inconsistency in a multi-level pointer declaration like char const* const p;
, where the last const
can't be moved. Which exemplifies that the equivalence is only for the base type at the start of a declaration.
Some months ago I started an experiment writing const T
, and using that notation consistently. Because that's now possible after C++11, without using macros. To support the consistency I use named type builders like
template< class Some_type >
using Ptr_ = Some_type*;
so that instead of the read-from-right-to-left
char const* const p = something;
I can and do write the ordinary reading direction
const Ptr_<const char> p = something;
It's little bit more verbose, but I now, with some experience using it, think it's worth it (I was not sure about that, it was an experiment).
The main drawback is that while this notation supports type deduction for (function template) function arguments just like direct use of C syntax, it does not support type deduction for auto
declarations. Happily, since an initializer can easily be made const
, about the only problematic case is reference to array. My pragmatic solution so far has been to use the C (or rather, C++) syntax directly in such cases, but I think this represents a shortcoming of or hole in the language, possibly with some general solution that would make things much easier also in other contexts.
For my current type builders like Ptr_
, see the cppx/core_language_support/type_builders.hpp file at Github. They include e.g. In_
for function arguments. And yes, I've found that also worth it, in clarity, in spite of some verbosity, because it makes the intent very clear. However, the cppx stuff is experimental and subject to change. The specific file linked to here may even be moved, but it will be thereabouts. :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With