检查指针是否指向数组

fre*_*low 14 c++ arrays comparison pointers

我可以检查给定指针是否指向由其边界指定的数组中的对象?

template <typename T>
bool points_within_array(T* p, T* begin, T* end)
{
    return begin <= p && p < end;
}
Run Code Online (Sandbox Code Playgroud)

或者,如果p指向数组范围之外的点,指针比较是否会调用未定义的行为?在那种情况下,我该如何解决这个问题?它是否适用于void指针?还是不可能解决?

Cas*_*Cow 10

虽然比较仅对数组中的指针和"一个结束"之间的指针有效,但使用带有指针的集合或映射作为键是有效的,它使用 std::less<T*>

1996年在comp.std.c ++上对这种方式进行了大量讨论

  • 但是,当你将`std :: less`应用于来自不同对象的指针时,并不要求在第二个范围的边界之间不对一个范围中的一个进行排序,这使得你可以比较它们没有实际意义. (3认同)

Jon*_*Jon 7

直接来自MSDN文档:

两个不同类型的指针无法比较,除非:

  • 一种类型是从另一种类型派生的类类型.
  • 至少有一个指针被显式转换(强制转换)为void*类型.(另一个指针隐式转换为类型void*进行转换.)

所以a void*可以与其他任何东西(包括另一个void*)进行比较.但这种比较会产生有意义的结果吗?

如果两个指针指向同一个数组的元素或指向超出数组末尾的元素,则指向具有较高下标的对象的指针会比较高.只有当指针引用同一数组中的对象或超出数组末尾的位置时,才能保证指针的比较有效.

看起来不是.如果您还不知道要比较数组中的项目(或刚刚超过它),则不能保证比较有意义.

但是,有一个解决方案:STL提供std::less<>std::greater<>,它将适用于任何指针类型,并将在所有情况下产生有效的结果:

if (std::less<T*>()(p, begin)) {
    // p is out of bounds
}
Run Code Online (Sandbox Code Playgroud)

更新:

这个问题的答案给出了相同的建议(std::less),并引用了标准.

  • 我不会引用MSDN作为确定的C++源代码,因为它通常是不准确的或MS特定的. (3认同)

Max*_*kin 5

当您将指向不位于同一数组中的对象的指针进行比较时,C ++标准未指定会发生什么,因此行为不确定。但是,C ++标准不是您的平台必须遵循的唯一标准。诸如POSIX之类的其他标准将C ++标准保留为未定义行为。在具有虚拟地址空间的平台(例如Linux和Win32 / 64)上,您可以比较任何指针而不会引起任何未定义的行为。


CB *_*ley 5

这样做的唯一正确方法是这样的方法.

template <typename T>
bool points_within_array(T* p, T* begin, T* end)
{
    for (; begin != end; ++begin)
    {
        if (p == begin)
            return true;
    }
    return false;
}
Run Code Online (Sandbox Code Playgroud)

显然,如果这不起作用T == void.我不确定两者是否在void*技术上定义了一个范围.当然,如果你有Derived[n],那么说(Base*)Derived, (Base*)(Derived + n)定义一个有效的范围是不正确的,所以我看不出它是有效的定义范围除了指向实际数组元素类型的指针.

下面的方法失败,因为<如果两个操作数不指向同一对象的成员或同一数组的元素,则未指定返回的内容.(5.9 [expr.rel]/2)

template <typename T>
bool points_within_array(T* p, T* begin, T* end)
{
    return !(p < begin) && (p < end);
}
Run Code Online (Sandbox Code Playgroud)

下面的方法失败,因为std::less<T*>::operator()如果两个操作数没有指向同一个对象的成员或同一个数组的元素,那么它也是未指定的.

确实,std::less如果内置的<没有,则必须专门针对任何指针类型产生总订单,但这仅对诸如为set或提供密钥等用途有用map.不能保证总顺序不会将不同的数组或对象交错在一起.

例如,在分段存储器架构上,对象偏移可以用作<并且作为std::less<T*>用于断开关系的段索引的最重要的区别.在这样的系统中,可以在第二个不同阵列的边界之间排序一个阵列的元素.

template <typename T>
bool points_within_array(T* p, T* begin, T* end)
{
    return !(std::less<T*>()(p, begin)) && (std::less<T*>()(p, end));
}
Run Code Online (Sandbox Code Playgroud)