5

我很难在索引类型之间进行选择size_tptrdiff_t它应该能够存储负值。

准确地说,在我的代码中,我需要实现一个数组。我将它的长度(在构造函数中)作为 的类型接收size_t,当我重载时,[] operator我需要索引是类型ptrdiff_t(而不是size_t),因为我想允许负索引,如本例所示:

std::size_t length = 50;
MyVector<int> vec(length);
vec[0] = 10;

MyVector<int> vec2 = vec+1;
std::cout << vec2[-1] << std::endl; //should print 10

上述设计产生的问题是可用索引的范围受到 的最大值的限制ptrdiff_t,并且在某些机器中,该上限小于 的最大值size_t

IEstd::numeric_limits<std::ptrdiff_t>::max() < std::numeric_limits<std::size_t>::max()

因此,问题是用户可能会创建一个大小大于最大值的数组ptrdiff_t(但仍然在 的范围内size_t,当然),但他将无法访问成功超过的数组元素的最大值ptrdiff_t,因为它们的索引会溢出到负数。在我的机器上,这将可用索引减半!(因为size_tptrdiff_t都是 64 位,但一个是unsigned另一个是signed

以下是我想出的解决方案,但遗憾的是它们都不是完美的:

  1. 在构造函数中,接受 type 的长度ptrdiff_t而不是size_t,并添加一个检查以验证给定的长度是否为负数。

    优点:它解决了这个问题,因为现在我将能够访问数组中的所有元素,并且仍然允许负索引。

    缺点:它限制了数组的最大可能长度。(例如,就像我之前说的,在我的机器中它减半)

  2. 保持原样,但在 中[] operator,将索引转换为 type size_t,并利用负值会溢出的事实。

    即到给定的索引,添加我们当前指向的元素和

    例如,在我之前的示例中,由于 vec2 指向数组中的第二个元素,因此[] operator看起来像

    template<class T>
    T& MyVector<T>::operator[] (std::ptrdiff_t index) {
        //Since vec2 points to the second element, we add 1.
        //For vec, we would add 0 since it points at the 
        //first element in the array.
        std::size_t actual_index = static_cast<std::size_t>(index + 1);
    
        //Do boundary checking
    
        return this->ptr[actual_index];
    }
    

    优点:我们现在可以访问数组中的所有元素。

    缺点:使用变得笨拙和丑陋。例如,如果我们创建一个 size 的向量std::numeric_limits<std::size_t>::max(),那么为了访问最后一个元素,我们需要访问 '-1' 元素:

    MyVector<int> big_vector(std::numeric_limits<std::size_t>::max());
    big_vector[-1] = 5; // big_vector[-1] is the last element in the array.
    
    MyVector<int> big_vector2 = big_vector + 1;
    std::cout << big_vector2[-2] << std::endl; // would print 5, since big_vector2 points at the second element in the array
    
4

1 回答 1

0

我很难在 size_t 和 ptrdiff_t 之间选择索引类型,它应该能够存储负值。

为什么你把自己限制在 size_t 和 ptrdiff_t?其他整数类型呢?

你有实际的计划来实现一个包含 4.294.967.296 个元素的容器吗?(即2 ^ 32)。

我认为今天没有一个平台可以分配那么多内存——至少在消费级计算机中没有。你在做专门的硬件吗?

对于通用 C++,您可以安全地将std::size_t- 接受构造函数写入std::ptrdiff_t索引类。

您可能必须配置接受的索引范围,以便如果您接受负索引,则有效索引范围应为 (-max32bit, max32bit)。

这意味着,如果您尝试使用具有范围内索引的类(max32bit,max64bit),您的类应该抛出异常。

我的解决方案将std::size_t在构造函数中接受 a (有明确的文档说明索引范围从 -max( ptrdiff_t) 到 max( ptrdiff_t),而不是从 0 到 max( std::size_t)。然后将使用std::ptrdiff_t.

于 2015-08-10T09:02:10.837 回答