Подтвердить что ты не робот

Является ли законным проверять, находится ли адрес подобъекта в пределах содержащегося объекта

2 Вопросы:

  • Является ли следующий код хорошо сформированным с определенным поведением?

  • Есть ли возможная реализация С++, в которой она могла бы утверждать?

Код (С++ 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()));
}

Обратите внимание, что a и b имеют разные спецификации доступа.

4b9b3361

Ответ 1

Сравнение указателей определяется в [expr.rel]/3-4:

Сравнение неравных указателей на объекты определяется следующим образом:

  • Если два указателя указывают на разные элементы одного и того же массива или на его подобъекты, указатель на элемент с более высоким индексом сравнивается больше.
  • Если два указателя указывают на разные нестатические данные членов одного и того же объекта или на подобъекты таких членов, рекурсивно, указатель на более поздний объявленный элемент сравнивается больше, если два члена имеют один и тот же контроль доступа и предоставили свой класс не является объединением.
  • В противном случае ни один указатель не сравнится больше другого.

Если два операнда p и q сравниваются равными, p <= q и p >= q оба дают true, а pq - false. В противном случае, если указатель p сравнивается больше, чем указатель q, p >= q, p > q, q <= p и q = p, а q > p все выдают false. В противном случае результат каждого из операторов не указан.

Какие выводы мы можем сделать из этого?

В объекте существует общий порядок указателей того же типа, но порядок указателей на разные объекты или разных подобъектов с различным контролем доступа отсутствует. Это отсутствие общего общего порядка указателей делает is_within_object() не очень значимым. В тех случаях, когда вы ожидаете возвращения true, он работает. В тех случаях, когда вы ожидаете возвращения false, результат этих операторов не указан? Это не очень полезный результат.


Этот сказал, что у нас есть гигантская лазейка для этого в виде [сравнения]:

Для шаблонов less, greater, less_­equal и greater_­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);
}