检查子对象的地址是否在包含对象的边界内是否合法

Is it legal to check whether the address of a subobject lies within the bounds of a containing object

本文关键字:对象 是否 边界 包含 地址 检查      更新时间:2023-10-16

2 问题:

  1. 以下代码是否具有定义的行为?

  2. 是否有任何可能的 c++ 实现可以断言?

代码(c++11 及更高版本):

#include <cassert>
#include <utility>
#include <ciso646>
template<class T> 
auto to_address(T* p) { return reinterpret_cast<unsigned char const*>(p); }
/// Test whether part is a sub-object of object
template<class Object, class Part>
bool is_within_object(Object& object, Part& part)
{
auto first = to_address(std::addressof(object)),
last = first + sizeof(Object);
auto p = to_address(std::addressof(part));
return (first <= p) and (p < last);
}
struct X
{
int a = 0;
int& get_a() { return a; }
int& get_b() { return b; }
private:
int b = 0;
};
int main()
{
X x;
assert(is_within_object(x, x.get_a()));
assert(is_within_object(x, x.get_b()));
}

请注意,ab具有不同的访问说明符。

指针比较在 [expr.rel]/3-4 中定义:

将不相等指针与对象的比较定义如下:

  • 如果两个指针指向同一数组的不同元素或其子对象,则指向具有较高下标的元素的指针会比较更大。
  • 如果两个指针指向同一对象的不同非静态数据成员,或指向此类成员的子对象,则指向后面声明的成员的指针在两个成员具有相同的访问控制并且它们的类不是联合的情况下进行比较。
  • 否则,两个指针的比较都不大于另一个指针。

如果两个操作数 p 和 q 比较相等,则 p<=q 和 p>=q 都产生 true,pq 都产生假。否则,如果指针 p 的比较大于指针 q,则 p>=q、p>q、q<=p 和 q=p,并且 q>p 都会产生 false。否则,未指定每个运算符的结果。

我们可以从中得出什么结论?

对象中相同类型的指针的总顺序,但指向不同对象或具有不同访问控制的不同子对象的指针没有顺序。由于缺乏指针的一般总顺序,is_within_object()意义不大。在您希望它返回true的情况下,它可以工作。在您希望它返回false的情况下,这些运算符的结果未指定?这不是一个非常有用的结果。


也就是说,我们确实有一个巨大的漏洞,以[比较]的形式出现:

对于模板lessgreaterless_­equalgreater_­equal,任何指针类型的专用化都会产生一个严格的总顺序,这些专用化在这些专用化之间是一致的,并且也与内置运算符<><=>=强加的偏序一致。

因此,以下内容将得到明确定义:

template<class T> 
auto byte_address(T& p) {
return reinterpret_cast<std::byte const*>(std::addressof(p));
}
template<class Object, class Part>
bool is_within_object(Object& object, Part& part)
{
auto first = byte_address(object);
auto last = first + sizeof(Object);   
auto p = byte_address(part);

return std::less_equal<std::byte*>{}(first, p) &&
std::less<std::byte*>{}(p, last);
}