Const member constant in const member function

How is const applied to a template member in a const member function? I found the following interesting (this is in VS15):

 class TcpSocket; class TcpThread { TcpSocket* Listener() const; std::vector< TcpSocket* > sockets_; }; TcpSocket* TcpThread::Listener() const { auto s = sockets_.front(); return s; } 

I added auto to clarify what happens. It is displayed as TcpSocket* , so a non-constant version of front is selected. However, if I insert

 sockets_.erase(sockets_.begin()); 

as the first line of code, it cannot compile, essentially saying that sockets_ is const .

It makes sense to work as it is, but here, obviously, more is happening than just "treating each element as const in the function of the const member.

+5
source share
4 answers

sockets_ inside the Listener is const . Let's see what front returns:

 reference front(); const_reference front() const; 

So, we get const_reference , in this case a TcpSocket * const& .

In this case, your expectation is incorrect. By canceling the link for clarity, you expect const TcpSocket* , it gives you TcpSocket * const . The first is a pointer to const TcpSocket , the last is a pointer to const to TcpSocket .

So that front gives you a pointer that you cannot change to a TcpSocket , which you can change.

Thus, this is absolutely true in order to make a non-constant copy of this pointer with its access point available for modification:

 auto s = sockets_.front(); //sockets_.front() returns TcpSocket* const //s copies it to a TcpSocket* 
+3
source

It's not that the non-constant version of front is called, it just stores pointers, and then you put it in auto , which always outputs by value (and not by reference - for which you need auto& = ). Since you are copying the const pointer, you have your own copy, so const is omitted for it unless you explicitly define it that way. This is why you TcpSocket* instead of TcpSocket* const .

If you want to check this out, try making auto& s = _sockets.front() and see what type you get.

Note. that since you are saving a pointer, the vector::const_reference that you return will point to a const pointer, not a pointer to const.

The container itself, which is a constant in this area, means that you cannot change your sequence of elements or what they point to. Therefore, you cannot say _sockets.erase() and you cannot say _sockets[0] . However, since the elements themselves are pointers to a non-const TcpSocket , this means that you can do whatever you want with them. This is a container that you cannot play with.

+2
source

Even if std::vector< TcpSocket* > sockets_; const itself, then the contained one (i.e. TcpSocket* ) is not const .

That is why you get the deduction not const .

+1
source

Why don't you get TcpSocket * const :

Although front() returns TcpSocket* const & , auto TcpSocket* .

Consider:

 double const & foo(); // ... double const a = 4.0; auto b = a; // valid, decltype(b) === double double c = a; // valid, too double d = foo(); // valid auto e = foo(); // decltype(e) === double 

You still make a copy, so why would this copy be const ? You do not get anything meaningful from the fact that s is TcpSocket * const .

Why don't you get TcpSocket const * :

This is simply because you store TcpSocket* in a vector. const n front() ensures that the saved pointer will not be changed (i.e. you cannot make sockets_.front() to another TcpSocket from Listener() ), but in order to save const correction of the object pointed to by per user.

0
source

Source: https://habr.com/ru/post/1241425/


All Articles