I thought that the correct type to use to store the difference between pointers was ptrdiff_t
.
我认为用来存储指针之间差异的正确类型是ptrdiff_t。
As such, I'm confused by the way that my STL
(msvc 2010) implements it's std::vector::size()
function. The return type is size_t
(this is mandated by the standard, as far as I understand it) and yet it's computed as the difference of pointers:
因此,我对我的STL (msvc 2010)实现它的方式感到困惑:std:::vector: size()函数。返回类型是size_t(根据我的理解,这是标准要求的),但是它是作为指针的差值计算的:
// _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's a bit of meta-magic that goes on in order to determine exactly what types size_type
and pointer
are. In order to be "sure" what types they are I checked this:
显然,要确定size_type和指针是什么类型,还需要进行一些元魔法。为了确定它们是什么类型,我检查了一下:
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
:
使用/Wall编译下面的代码,我得到了mysize2的一个签名到未签名的不匹配,但是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 the type of mysize2
to ptrdiff_t
results in no warning. Changing the type of mysize1
to ptrdiff_t
results in an unsigned-to-signed mismatch
.
将mysize2类型更改为ptrdiff_t将导致无警告。将mysize1类型更改为ptrdiff_t会导致未签名到签名的不匹配。
Obviously I'm missing something...
显然我少了什么……
EDIT: I'm not asking how to suppress the warning, with a cast or a #pragma disable(xxx)
. The issue I'm concerned about is that size_t
and ptrdiff_t
may have different allowable ranges (they do on my machine).
编辑:我并不是问如何通过强制转换或#pragma disable(xxx)来抑制警告。我担心的问题是size_t和ptrdiff_t可能有不同的允许范围(它们在我的机器上有)。
Consider std::vector<char>::max_size()
. My implementation returns a max_size
equal to std::numeric_limits<size_t>::max()
. Since vector::size()
is creating an intermediate value of type ptrdiff_t
before casting to size_t
it seems that there could be problems here - ptrdiff_t
is not big enough to hold vector<char>::max_size()
.
考虑std::向量< char >::max_size()。我的实现返回一个max_size,等于std::numeric_limits
2 个解决方案
#1
6
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
.
一般来说,ptrdiff_t是与size_t大小相同的有符号积分类型。它必须有符号,这样它就可以代表p1 - p2和p2 - p1。
In the specific case of the internals of std::vector, the implementor is effectively deriving size()
from end() - begin()
. Because of the guarantees of std::vector (contiguous, array based storage), the value of the end pointer will always be greater than the value of the begin pointer, and thus there is no risk of generating a negative value. In fact, size_t will always be able to represent a larger positive range than will ptrdiff_t, as it doesn't have to use half its range to represent negative values. Effectively, this means that the cast in this case from ptrdiff_t to size_t is a widening cast, which has well defined (and intuitively obvious) results.
在std::vector的内部情况中,实现者有效地从end() - begin()派生出size()。由于std::vector(连续的,基于数组的存储)的保证,结束指针的值总是大于开始指针的值,因此不存在生成负值的风险。实际上,size_t总是能够比ptrdiff_t表示一个更大的正值范围,因为它不需要用它的一半的值域来表示负值。有效地说,这意味着从ptrdiff_t到size_t的强制转换是一种扩展的强制转换,它具有很好的定义(直观地很明显)结果。
Also, note that this is not the only possible implementation of std::vector. It could just as easily be implemented as a single pointer and a size_t value holding the size, deriving end()
as begin() + size()
. That implementation would also resolve your max_size()
concern. In reality, max_size is never actually attainable--it would require your program's entire address space to be allocated for the vector's buffer, leaving no room for the begin()/end() pointers, function call stack, etc.
另外,请注意,这并不是std::vector的唯一可能实现。它可以很容易地实现为一个指针和一个size_t值,包含大小,派生end()和begin() + size()。该实现还将解决您的max_size()问题。实际上,max_size实际上是不可能实现的——它需要您的程序的整个地址空间被分配给vector的缓冲区,而不为begin()/end()指针、函数调用堆栈等提供空间。
#2
0
There is nothing wrong with how std::vector::size() is implemented in STL. The this->_Mylast - this->_Myfirst == vector size is mere an coincidental fact which relies on how the vector is implemented.
std::vector::size()在STL中实现没有问题。这个->_Mylast ->_Myfirst =向量大小仅仅是一个巧合的事实,它依赖于向量是如何实现的。
Plus MSVC STL vector implementation has an #pragma warning(disable: 4244) which removes the warning.
加上MSVC STL向量实现有一个#pragma警告(禁用:4244),它删除了警告。
#1
6
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
.
一般来说,ptrdiff_t是与size_t大小相同的有符号积分类型。它必须有符号,这样它就可以代表p1 - p2和p2 - p1。
In the specific case of the internals of std::vector, the implementor is effectively deriving size()
from end() - begin()
. Because of the guarantees of std::vector (contiguous, array based storage), the value of the end pointer will always be greater than the value of the begin pointer, and thus there is no risk of generating a negative value. In fact, size_t will always be able to represent a larger positive range than will ptrdiff_t, as it doesn't have to use half its range to represent negative values. Effectively, this means that the cast in this case from ptrdiff_t to size_t is a widening cast, which has well defined (and intuitively obvious) results.
在std::vector的内部情况中,实现者有效地从end() - begin()派生出size()。由于std::vector(连续的,基于数组的存储)的保证,结束指针的值总是大于开始指针的值,因此不存在生成负值的风险。实际上,size_t总是能够比ptrdiff_t表示一个更大的正值范围,因为它不需要用它的一半的值域来表示负值。有效地说,这意味着从ptrdiff_t到size_t的强制转换是一种扩展的强制转换,它具有很好的定义(直观地很明显)结果。
Also, note that this is not the only possible implementation of std::vector. It could just as easily be implemented as a single pointer and a size_t value holding the size, deriving end()
as begin() + size()
. That implementation would also resolve your max_size()
concern. In reality, max_size is never actually attainable--it would require your program's entire address space to be allocated for the vector's buffer, leaving no room for the begin()/end() pointers, function call stack, etc.
另外,请注意,这并不是std::vector的唯一可能实现。它可以很容易地实现为一个指针和一个size_t值,包含大小,派生end()和begin() + size()。该实现还将解决您的max_size()问题。实际上,max_size实际上是不可能实现的——它需要您的程序的整个地址空间被分配给vector的缓冲区,而不为begin()/end()指针、函数调用堆栈等提供空间。
#2
0
There is nothing wrong with how std::vector::size() is implemented in STL. The this->_Mylast - this->_Myfirst == vector size is mere an coincidental fact which relies on how the vector is implemented.
std::vector::size()在STL中实现没有问题。这个->_Mylast ->_Myfirst =向量大小仅仅是一个巧合的事实,它依赖于向量是如何实现的。
Plus MSVC STL vector implementation has an #pragma warning(disable: 4244) which removes the warning.
加上MSVC STL向量实现有一个#pragma警告(禁用:4244),它删除了警告。