【发布时间】:2018-06-16 07:25:18
【问题描述】:
我想要一个函数来检查指针是否指向向量的元素:
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)。
这个分析正确吗?有没有更好的方法来检查指针是否在一定范围内?
(注意:有几个类似的问题,但没有一个考虑使用强制转换为 intptr_t 的可能性)。
【问题讨论】:
-
intptr_t不是你的朋友:与比较普通指针相比,比较它的保证更少。例如,甚至不能保证单个指针能够可靠地转换为单个整数(但所有这些整数都必须convert back to the same pointer)。 -
@DavisHerring 它的意图是
uintptr_t具有到整数的自然映射 -
当然是有意的:第 4 段是这么说的。它是由实现定义的,而不是未指定的,所以你的实现很可能会说它很好而且很明显。但这并不能使
intptr_t改进内置指针比较,后者是未指定,而不是未定义行为。 -
@DavisHerring 感谢您的更正。我认为比较不相关的指针是未定义的行为,但根据stackoverflow.com/questions/31774683/…,只有减去不相关的指针才是 UB,比较它们只是未指定的行为。对吗?
-
是的,那是expr.add/5,它还包括在同一个数组中减去相距太远的指针的不幸情况(通常只对
char*可能)。