【发布时间】:2015-03-02 05:25:15
【问题描述】:
我希望实现一个函数来确定给定指针是否指向给定缓冲区。规格:
template <typename T>
bool points_into_buffer (T *p, T *buf, std::size_t len);
如果有一些n,0 <= n && n < len,对于其中p == buf + n,返回true。
否则,如果有一些n,0 <= n && n < len * sizeof(T),其中reinterpret_cast<char *>(p) == reinterpret_cast<char *>(buf) + n,则行为未定义。
否则,返回false。
明显的实现看起来像
template <typename T>
bool points_into_buffer (T *p, T *buf, std::size_t len) {
return p >= buf && p < buf + len;
}
但这在标准 C++ 中具有未定义的行为:指针的关系比较仅针对指向同一数组的指针定义。
另一种方法是使用标准库的比较器对象:
template <typename T>
bool points_into_buffer (T *p, T *buf, std::size_t len) {
return std::greater_equal<T *>()(p, buf) && std::less<T *>()(p, buf + len);
}
当我希望它返回true 时,它保证返回true,并避免未定义的行为,但允许误报:给定int a; int b;,它允许points_into_buffer(&a, &b, 1) 的结果为true。
可以实现为循环:
template <typename T>
bool points_into_buffer (T *p, T *buf, std::size_t len) {
for (std::size_t i = 0; i != len; i++)
if (p == buf + i)
return true;
return false;
}
但是,编译器在优化该循环时遇到了麻烦。
是否有一种有效的编写方式,在启用当前编译器和优化的情况下,结果是在恒定时间内确定的?
【问题讨论】:
-
是什么让您认为使用比较函子不会导致未定义的行为?它们被定义为使用普通的关系运算符,因此这里应该没有区别。
-
@Horstling C++11 [comparisons]p8 "对于模板
greater、less、greater_equal和greater_equal和less_equal,任何指针类型的特化都会产生一个总顺序,甚至如果内置运算符<、>、<=、>=没有。" -
@hvd 有趣(而且有点违反直觉)。不知道那个,谢谢。
-
从语言律师的角度来看,这根本没有帮助,但在实践中知道即使是 GNU 可移植性库 (gnulib) makes the same assumption 似乎也没有帮助据报道,这在现实世界的平台上会中断。
-
@jdlugosz 这又假设了一个线性地址空间,这很常见,但不是通用的,我想避免假设。
标签: c++ pointers undefined-behavior