Is there any safe way to derive the offset of a T inside a std::optional<T>?

133 views Asked by At

Given a std::optional<T> is it possible to derive the address of the std::optional<T> from the address of the T?

possible implementation:

template<typename T>
struct myoptional
{       static std::size_t getOffset(void)
        {       static const myoptional<T> s(std::inplace());
                return reinterpret_cast<const char*>(&s.value())
                       - reinterpret_cast<const char*>(&s);
        };
};
1

There are 1 answers

4
user17732522 On

It is not specified where exactly in its storage std::optional stores the object. If you assume that the location of the object is always the same for the same type T, you can maybe (see below) use the shown method to obtain an offset through the object representation.

However, even if you knew the offset of the object, you would still not be able to obtain a usable pointer to the std::optional<T> from a pointer to the T object. You would need to std::launder the resulting pointer to make it usable, which will only be allowed if sizeof(std::optional<T>) <= sizeof(T), which seems unlikely/impossible. (Otherwise it would make previously unreachable bytes reachable in the meaning of the term reachable as in the preconditions for std::launder, see https://en.cppreference.com/w/cpp/utility/launder)


Whether or not the use of the reinterpret_cast and the pointer arithmetic is allowed by the standard is not clear at the moment. The standard has some unresolved defects in that regard.

What you can do alternatively though and (as far as I can tell) shouldn't have undefined behavior is to use a union of a std::optional<T> with a unsigned char[sizeof(std::optional<T>)] and instead of using a pointer difference, you can then use addition and pointer comparison in a loop to find the offset in the character array matching the address of the T value. See e.g this answer.