How do we know that a compiler will use const_iterator?

Say for example i have this code

1
2
3
4
5
6
7
8
9
10
11
12
class SceneNode 
{
public:
	typedef std::unique_ptr<SceneNode> Ptr;
	SceneNode();



private:
	std::vector<Ptr> mChildren;
	SceneNode* mParent;
}


In my main:
1
2
3
4
5
6
7
for (std::vector<Ptr>::const_iterator ittr = mChildren.begin(); ittr != mChildren.end(); ++ittr){

	}

	for (auto itr = mChildren.begin(); itr != mChildren.end(); ++itr){
		(*itr)->draw(target, states);
	}


That two for loop is the same
The 1st loop, I manually use const_iterator but I didnt use any constant reference to my vector? So how does the compiler deduce to this type?

2nd loop, the compiler will deduce its type.


My
std::vector<Ptr> mChildren;
is not const

Why is that? I also didnt use cbegin() and cend()
Last edited on
The IS requires that for a standard container C, C::iterator must be implicitly convertible to C::const_iterator.

See the picture that Scott Meyers has drawn here:
http://www.drdobbs.com/cpp/three-guidelines-for-effective-iterator/184401406
And if you will read article, please not that it is outdated: in C++11 standard library was fixed and allows usage of const_iterators in all sensible places. In Effective Modern C++ Scott Meyers now advises to use const_iterators if possible and discuss changes made in C++11 (Item 13)
But do you know why it prefers const iterators? I didnt use any const on my code so i wonder why does the compiler use const iterator
I didnt use any const on my code

You declared ittr as a const_iterator.
OW no no. I merely put it to show that the compiler is okay with const_iterator rather that iterator only. Putting auto makes it const_iterator. It was just for illustration. My concern is how and why does compiler go to const_iterator even if my vector isnt constant
Putting auto makes it const_iterator
Are you sure? How did you determine?
Is your member function marked as const?
> My concern is how and why does compiler go to const_iterator even if my vector isnt constant

It does not.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <vector>
#include <type_traits>
#include <iostream>

int main()
{
    std::vector<int> vec ;
    const auto& const_vec = vec ;
    
    auto iter = vec.begin() ;
    static_assert( std::is_same< decltype(iter), std::vector<int>::iterator >::value, "must be std::vector<int>::iterator" ) ;

    auto citer = const_vec.begin() ;
    static_assert( std::is_same< decltype(citer), std::vector<int>::const_iterator >::value, "must be std::vector<int>::const_iterator" ) ;
    
    static_assert( std::is_convertible< std::vector<int>::iterator, std::vector<int>::const_iterator >::value, 
                                        "there must be an implicit converstion from iterator to const_iterator" ) ;
                                        
    static_assert( !std::is_convertible< std::vector<int>::const_iterator, std::vector<int>::iterator >::value, 
                                        "there can't be an implicit converstion from const_iterator to iterator" ) ;
                                        
    std::cout << "ok.\n" ;                                    
}

http://coliru.stacked-crooked.com/a/24ce2f648e682cb0
http://rextester.com/NVC71946
Here is the whole code

.h file

1
2
3
4
5
6
7
8
9
10
11
public:
	typedef std::unique_ptr<SceneNode> Ptr;
	SceneNode();

	void  attachChild(Ptr child);
	Ptr detachChild(const SceneNode& node);

private:
	std::vector<Ptr> mChildren;
	SceneNode* mParent;
virtual  void  draw(sf::RenderTarget &target, sf::RenderStates states) const final;


1
2
3
4
5
6
7
8
9
10
11
void SceneNode::draw(sf::RenderTarget &target, sf::RenderStates states) const{
	states.transform *= getTransform();

	for (std::vector<Ptr>::const_iterator ittr = mChildren.begin(); ittr != mChildren.end(); ++ittr){
		(*ittr)->draw(target, states);
	}

	for (auto itr = mChildren.begin(); itr != mChildren.end(); ++itr){
		(*itr)->draw(target, states);
	}
}


Your SceneNode function is const. That means every member is implicitely const inside it. begin() returns const_iterator in const context
Last edited on
I see.. So that is how it affects.

Thanks

Const is sometimes confusing
> Const is sometimes confusing

Does this alleviate the confusion?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>

struct A
{
    const int c = 45 ; // always const
    int i = 67 ; // const in const A, non-const in non-const A
    mutable int m = 92 ; // never const

    void foo() const ; // operates on an object of type const A
    void bar() ; // operates on an object of type (non-const) A
};

void test_it( const A* ) { std::cout << "pointer to const A\n" ; }
void test_it( A* ) { std::cout << "pointer to (non-const) A\n" ; }
void test_it( const A& ) { std::cout << "const A\n" ; }
void test_it( A& ) { std::cout << "(non-const) A\n" ; }
void test_it( const int& ) { std::cout << "const int\n" ; }
void test_it( int& ) { std::cout << "(non-const) int\n" ; }

#define TEST_IT(x) { std::cout << #x ":\t" ; test_it(x) ; }

void A::foo() const
{
    std::cout << "A::foo() const => " ;
    TEST_IT(this) ;
}

void A::bar()
{
    std::cout << "A::bar() (non-const) => " ;
    TEST_IT(this) ;
}

void baz( const A& ca, A& a )
{
    TEST_IT(ca) ; // ca: const A
    TEST_IT( ca.c ) ; // ca.c: const int
    TEST_IT( ca.i ) ; // ca.i: const int
    TEST_IT( ca.m ) ; // ca.m: (non-const) int
    std::cout << "ca.foo() => " ; ca.foo() ; // ca.foo() => A::foo() const => this: pointer to const A

    std::cout << "\n\n" ;

    TEST_IT(a) ; // a: (non-const) A
    TEST_IT( a.c ) ; // a.c: const int
    TEST_IT( a.i ) ; // a.i: (non-const) int
    TEST_IT( a.m ) ; // a.m: (non-const) int
    std::cout << "a.foo() => " ; a.foo() ; // a.foo() => A::foo() const => this: pointer to const A
    std::cout << "a.bar() => " ; a.bar() ; // a.bar() => A::bar() (non-const) => this: pointer to (non-const) A
}

int main()
{
    A a ;
    baz( a, a ) ;
}

clang++ -std=c++14 -stdlib=libc++ -O2 -Wall -Wextra -pedantic-errors -Wno-unused-parameter main.cpp -lsupc++ && ./a.out 

ca:	const A
ca.c:	const int
ca.i:	const int
ca.m:	(non-const) int
ca.foo() => A::foo() const => this:	pointer to const A


a:	(non-const) A
a.c:	const int
a.i:	(non-const) int
a.m:	(non-const) int
a.foo() => A::foo() const => this:	pointer to const A
a.bar() => A::bar() (non-const) => this:	pointer to (non-const) A

http://coliru.stacked-crooked.com/a/bb82f41bb9786b06
Topic archived. No new replies allowed.