检查指针是否指向向量元素

时间:2018-06-16 07:25:19

标签: c++ undefined-behavior

我想要一个函数来检查指针是否指向向量的元素:

template <typename T>
bool pointsToElement(const std::vector<T>& vec, const T* ptr);

该函数是一个辅助函数,用于从指针安全地创建迭代器:

template <typename T>
std::vector<T>::iterator toIterator(std::vector<T>& vec, T* ptr)
{
    assert(pointsToElement(vec, ptr));
    return vec.begin() + (ptr - &vec[0]);
}

“显而易见”的方式是:

template <typename T>
bool pointsToElement(const std::vector<T>& vec, const T* ptr)
{
    if (vec.empty())
        return false;
    return ptr >= &vec.front() && ptr <= &vec.back();
}

不幸的是,这似乎调用了未定义的行为,因为它可能会将指针与不同的对象进行比较。

安全的方法是:

template <typename T>
bool pointsToElement(const std::vector<T>& vec, const T* ptr)
{
    for (auto& elem : vec) {
        if (&elem == ptr)
            return true;
    }
    return false;
}

但这当然是O(N),所以非常不受欢迎。

我可以想象另一种方式:

template <typename T>
bool pointsToElement(const std::vector<T>& vec, const T* ptr)
{
    if (vec.empty())
        return false;
    intptr_t pos   = reinterpret_cast<intptr_t>(ptr);
    intptr_t begin = reinterpret_cast<intptr_t>(&vec.front());
    intptr_t end   = reinterpret_cast<intptr_t>(&vec.back());
    return pos >= begin && pos <= end;
}

我认为标准不保证inptr_t的任何排序,但这至少不应该调用任何未定义的行为并在主要平台上产生正确的结果(我现在只关心Linux和Windows)。 / p>

这种分析是否正确?有没有更好的方法来检查指针是否落在某个范围内?

(注意:有一些类似的问题,但没有人考虑使用强制转换为intptr_t的可能性。)

2 个答案:

答案 0 :(得分:4)

这是std::lessstd::greater派上用场的其中一种情况。

  

对于任何指针类型,std :: less的特化产生严格的总顺序,即使内置运算符&lt;才不是。对于该指针类型,严格的总顺序在std :: less,std :: greater,std :: less_equal和std :: greater_equal的特化之间是一致的,并且与相应的内置运算符强加的部分顺序一致(&lt;,&gt;,&lt; =和&gt; =)。

通过这些保证,您可以使用“明显”的解决方案。

DavisHerring在评论中指出,可能存在具有分段存储器布局的架构,其中无关指针可以在两个向量元素之间排序,并且仍然符合严格的总顺序。

答案 1 :(得分:1)

首先:

如果您需要检查指针是否有效,则存在一般设计问题!您必须考虑谁拥有数据以及指向此数据的指针有效期。

为了你的想法建立一个&#34;检查&#34;一个指针指向一个向量的元素:

open .

但这会有什么帮助?

如果你的指针被赋值给某个向量的某个元素,然后在向量上重新分配了一些时间,那么它可能会再次出现在那个地方但是会移走一些元素。

一般情况下:如果您的设计可能会导致悬挂指针,那么以后进行运行时检查是没有意义的。以后在运行时检查时无法修复损坏的设计!您的程序仍有&#34;未定义的行为!&#34;