Size_t, ptrdiff_t and std :: vector :: size ()

I thought the correct type for storing the difference between pointers was ptrdiff_t .

Thus, I am confused by the fact that my STL (msvc 2010) implements the function std::vector::size() . The type of the return value is size_t (this, in my opinion, corresponds to the standard, and, nevertheless, it is calculated as the difference of pointers:

 // _Mylast, _Myfirst are of type pointer // size_type, pointer are inherited from allocator<_Ty> size_type size() const { return (this->_Mylast - this->_Myfirst); } 

Obviously, there is a bit of metamagy going on to pinpoint the types size_type and pointer . To be sure what types they are, I tested this:

 bool bs = std::is_same<size_t, std::vector<int>::size_type>::value; bool bp = std::is_same<int * , std::vector<int>::pointer>::value; // both bs and bp evaluate as true, therefore: // size_type is just size_t // pointer is just int* 

Compiling the following with /Wall gives me a signed-to-unsigned mismatch for mysize2 , but no warnings for mysize1 :

 std::vector<int> myvector(100); int *tail = &myvector[99]; int *head = &myvector[ 0]; size_t mysize1 = myvector.size(); size_t mysize2 = (tail - head + 1); 

Changing mysize2 to ptrdiff_t does not result in a warning. Changing the type of mysize1 to ptrdiff_t results in an unsigned-to-signed mismatch .

Obviously, I missed something ...

EDIT: I am not asking how to suppress a warning with cast or #pragma disable(xxx) . The problem I'm worried about is that size_t and ptrdiff_t can have different valid ranges (they run on my machine).

Consider std::vector<char>::max_size() . My implementation returns a max_size equal to std::numeric_limits<size_t>::max() . Since vector::size() creates an intermediate value of type ptrdiff_t before proceeding to size_t , it seems that there may be problems - ptrdiff_t not large enough to hold vector<char>::max_size() .

+6
source share
2 answers

Generally speaking, ptrdiff_t is a signed integral type of the same size as size_t. It must be signed so that it can represent both p1 - p2 and p2 - p1 .

In the specific case of std :: vector internal elements, the developer effectively derives size() from end() - begin() . Due to the guarantees of std :: vector (continuous storage based on an array), the value of the final pointer will always be greater than the value of the start pointer, and therefore there is no risk of generating a negative value. In fact, size_t will always be able to represent a larger positive range than ptrdiff_t, since it should not use half of its range to represent negative values. Effectively, this means that casting from ptrdiff_t to size_t in this case is an expanding cast that has clearly defined (and intuitively obvious) results.

Also note that this is not the only possible implementation of std :: vector. It could be easily implemented as a single pointer and a size_t value having a size, getting end() as begin() + size() . This implementation will also solve your max_size() problem. In fact, max_size is never reachable - this requires that your full program address space be allocated for the vector buffer, leaving no room for begin () / end () pointers, a stack of function calls, etc.

+6
source

There is nothing wrong with the way std :: vector :: size () is implemented in STL. this → _ Mylast - this → _ Myfirst == vector size is just a random fact that depends on how the vector is implemented.

Plus, the implementation of the STL vector for MSVC has #pragma warning (disable: 4244) , which removes the warning.

0
source

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


All Articles