C++ Logo

std-proposals

Advanced search

[std-proposals] 回复: all bytes zero == null object

From: 李 秋逸 <qiuyili1023_at_[hidden]>
Date: Mon, 22 Jul 2024 15:23:20 +0000
Maybe we can go further. Here is my solution.
We add a template struct in namespace std.

template<class T>
struct invalid_state; //No definition

We can add a template specialization like this:

template<>
struct std::invalid_state<my_class>
{
        static constexpr size_t offset = ... ;
        static constexpr unsigned char state[] = {...};
}; //This means from the offset'th to (offset + sizeof(state))'th bytes of an object with type my_class can't be the same as state.

Here is an example:

template<class T>
class my_vector
{
        T* data; //8bytes
        size_t _size; //8bytes, can't be 0xffffffff
        //...
};

template<class T>
struct std::invalid_state<my_vector<T>>
{
        static constexpr size_t offset = 8 ;
        static constexpr unsigned char state[] = {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
};

Then std::optional< my_vector<T>> can use this to decide whether it has a value.

-----邮件原件-----
发件人: Std-Proposals <std-proposals-bounces_at_lists.isocpp.org> 代表 Frederick Virchanza Gotham via Std-Proposals
发送时间: 2024年7月22日 0:51
收件人: std-proposals <std-proposals_at_lists.isocpp.org>
抄送: Frederick Virchanza Gotham <cauldwell.thomas_at_gmail.com>
主题: [std-proposals] all bytes zero == null object

Typically when implementing a class such as 'std::optional', the size of 'std::optional<T>' is equal to "sizeof(T) + 1u", because one more byte is needed to store a boolean to indicate whether there is a valid object in existence.

We can use "__datasizeof" or "[[no_unique_address]]" in order to try use the tail padding of T to store the boolean, and if we succeed, then sizeof(optional<T>) == sizeof(T).

If T has no tail padding, then we need an extra byte to store the boolean. Unless . . . we had the ability to mark the class 'null_bytes==null_object" as follows:

    class T (null_bytes==null_object) {
        . . .
    };

Marking a class as 'null_bytes==null_object' means that a byte-pattern of all zeroes is a 'null object'. The standard header <type_traits> would then have "std::is_null_bytes_null_object".

So then "std::optional::has_value" could be:

    bool optional::has_value(void) noexcept requires is_null_bytes_null_object_v<T>
    {
        return (0u == *storage) && !memcmp(storage, storage + 1u,
sizeof(storage) - 1u);
    }

Another effect of marking a class as 'null_bytes==null_object' would be that the destructor doesn't get called. For instance the following program won't crash:

    struct T (null==0) {
        int a, b, c;
        ~T(void) { *(int*)nullptr = 666; }
    };

    int main(void)
    {
        T var = {0,0,0};
    }

The above program doesn't have undefined behaviour, because the destructor is treated as though it were written:

        ~T(void)
        {
            char const *const p = (char*)this;
            if ( (0u == *p) && !memcmp(p, p + 1u, sizeof(*this) - 1u) ) return;
            *(int*)nullptr = 0;
        }
--
Std-Proposals mailing list
Std-Proposals_at_[hidden]rg
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2024-07-22 15:23:25