What is the reason behind cbegin/cend?
It's quite simple. Say I have a vector:
std::vector<int> vec;
I fill it with some data. Then I want to get some iterators to it. Maybe pass them around. Maybe to std::for_each
:
std::for_each(vec.begin(), vec.end(), SomeFunctor());
In C++03, SomeFunctor
was free to be able to modify the parameter it gets. Sure, SomeFunctor
could take its parameter by value or by const&
, but there's no way to ensure that it does. Not without doing something silly like this:
const std::vector<int> &vec_ref = vec;
std::for_each(vec_ref.begin(), vec_ref.end(), SomeFunctor());
Now, we introduce cbegin/cend
:
std::for_each(vec.cbegin(), vec.cend(), SomeFunctor());
Now, we have syntactic assurances that SomeFunctor
cannot modify the elements of the vector (without a const-cast, of course). We explicitly get const_iterator
s, and therefore SomeFunctor::operator()
will be called with const int &
. If it takes it's parameters as int &
, C++ will issue a compiler error.
C++17 has a more elegant solution to this problem: std::as_const
. Well, at least it's elegant when using range-based for
:
for(auto &item : std::as_const(vec))
This simply returns a const&
to the object it is provided.
What is the differences between begin(),end() and cbegin() ,cend()?
cbegin: Returns a const_iterator pointing to the first element in the container.
begin: Returns an iterator pointing to the first element in the sequence.
cend: Returns a const_iterator pointing to the past-the-end element in the container.
end: Returns an iterator pointing to the past-the-end element in the sequence.
http://www.cplusplus.com/reference/map/map/cbegin/
http://www.cplusplus.com/reference/iterator/begin/?kw=begin
http://www.cplusplus.com/reference/map/map/cend/
http://www.cplusplus.com/reference/iterator/end/?kw=end
forcing use of cbegin()/cend() in range-based for
Update: std::as_const
will be in C++17, in the <utility>
header.
Prior to C++17, there's no built-in syntax for it; however, you can easily write a convenience wrapper:
template<typename T> constexpr const T &as_const(T &t) noexcept { return t; }
for (auto &v: as_const(container))
Note that this calls begin() const
rather than cbegin()
specifically; the Standard container general requirements specify that cbegin()
and begin() const
behave identically.
If your container treats non-const iteration specially, it might make sense for it itself to have a member function:
const Container &crange() const noexcept { return *this; }
for (auto &v: container.crange())
cbegin()/cend() vs constBegin()/constEnd()
cbegin()
and cend()
where introduced for compatibility with Standard Library containers, which all contain such functions since C++11.
Qt just wants to keep it interface similar to the standard library.constBegin()
etc. are just older versions (Qt added them before C++11 was released). There is no difference in using them.
I'd use constBegin()
and constEnd()
as they are more explicit and 'Qt style', but that just my personal preference. cbegin()
/cend()
might be used by some algorithms implemented for standard containers (hence their existence in Qt - they help reuse some code). Use them if you expect that at some point you would like to reuse your code outside Qt.
Container begin / end / cbegin / cend semantics, iterator / const_iterator compatibility
iterator begin ();
iterator end ();
const_iterator begin () const;
const_iterator end () const;
const_iterator cbegin () const;
const_iterator cend () const;
And yes, const_iterator it = iterator;
should work (but not the other way around), as should ==
(I am not certain the first is mandated, but you should still do it).
Also consider writing SCARY iterators, where the iterator is not a subtype of the container.
template<class T>
struct foo {
template<class U, std::enable_if_t<std::is_same_v<std::remove_cv_t<U>, std::remove_cv_t<T>>,bool> =true>
friend bool operator==( foo const& lhs, foo<U> const& rhs );
};
This is an example of a ==
that works between types.
What is the difference between cbegin and begin for vector?
begin
will return an iterator
or a const_iterator
depending on the const-qualification of the object it is called on.
cbegin
will return a const_iterator
unconditionally.
std::vector<int> vec;
const std::vector<int> const_vec;
vec.begin(); //iterator
vec.cbegin(); //const_iterator
const_vec.begin(); //const_iterator
const_vec.cbegin(); //const_iterator
Why does std::cbegin() not call .cbegin() on the container?
this fails because
std::cbegin()
calls the.begin()
To be more precise, std::cbegin
calls std::begin
, which in the generic overload calls c.begin
.
For what it's worth, it should be possible to fix gsl::span
to return const iterator upon std::cbegin
if the designers of gsl specify that there is a specialisation for the generic overload of std::cbegin
for gsl::span
that uses c.cbegin
instead of std::begin
, if that is the desired behaviour. I don't know their reasoning for not specifying such specialisation.
As for reasoning for why std::cbegin
uses std::begin
, I do not know for fact either, but it does have the advantage of being able to support containers that have a c.begin
member, but not a c.cbegin
member, which can be seen as a less strict requirement, as it can be satisfied by custom containers written prior to C++11, when there was no convention of providing a c.cbegin
member function.
Why does std::span lack cbegin and cend methods?
As an update, these are added back by P2278R4. The LWG issue pointed out below is still a problem, x.cbegin()
and std::cbegin(x)
would do different things, but now x.cbegin()
and std::ranges::cbegin(x)
do the same thing.
This was removed as a result of LWG3320.
The issue is that x.cbegin()
should really do the same thing as std::begin(std::as_const(x))
, which is what std::cbegin(x)
is defined as.
But that's not the case for std::span
, because it doesn't actually own its elements and, as a result, only has shallow const. Given span<int> s;
, s.cbegin()
would've given you an int const*
† while std::cbegin(s)
gives you an int*
. That's very inconsistent. Could've kept s.cbegin()
while having it just return begin()
(as proposed by PL 247), but that's arguably confusing, so the resolution decision was to simply remove all the const members and aliases.
In any case, std::cbegin(s)
always works if you want the container itself to be immutable (which isn't an issue with span
to begin with).
†Technically, implementation defined, not necessary int const*
, but this is a useful fiction for explanatory purposes.
Is cbegin/cend not enough for a range based for loop?
Do I have to implement begin/end?
Yes.
As far as I understood it, it should choose
cbegin/cend
if it'sconst auto &x
and notauto &x
.
That's not how the range-based for
is defined in the standard. Range-based for
always looks for begin()
and end()
. From https://timsong-cpp.github.io/cppwp/n3337/stmt.ranged.
otherwise, begin-expr and end-expr are
begin(__range)
andend(__range)
, respectively, wherebegin
andend
are looked up with argument-dependent lookup ([basic.lookup.argdep]). For the purposes of this name lookup, namespace std is an associated namespace.
Related Topics
How to Call a Pointer-To-Member-Function
How to Implement a Map with Different Data Types as Values
Ramifications of C++20 Requiring Two's Complement
Remote Debugging C++ Applications with Eclipse Cdt/Rse/Rdt
Does Reinterpret_Cast Lead to Undefined Behavior
C++ Templates: Conditionally Enabled Member Function
Free Function Versus Member Function
Why Implicit Conversion Is Harmful in C++
C++ Static_Cast Runtime Overhead
How to Use C++14 Features When Building Qmake Projects
How to Make a C++ Struct Value-Initialize All Pod Member Variables
What Does the Gcc Warning "Project Parameter Passing for X Changed in Gcc 7.1" Mean