C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Use the exception system to check for bases at runtime

From: Tiago Freire <tmiguelf_at_[hidden]>
Date: Tue, 2 Apr 2024 16:35:35 +0000
Another week another completely nonsensical suggestion.
Why do you keep doing this?
1. dynamic_cast already exists.
2. you could have done just this static_cast<B1*>(reinterpret_cast< Derived*>(&d)), and it does essentially the same without the overhead.

And again, you have absolutely no reason as to why you would even want to do this. Because there is none.
Never in my life as an engineer have I ever wondered how I can get a pointer to a thing that I already know what it is.
And I'm utterly perplexed as to why anyone would write this type of convoluted code.

Please stop.

-----Original Message-----
From: Std-Proposals <std-proposals-bounces_at_lists.isocpp.org> On Behalf Of Frederick Virchanza Gotham via Std-Proposals
Sent: Tuesday, April 2, 2024 17:58
To: std-proposals <std-proposals_at_lists.isocpp.org>
Cc: Frederick Virchanza Gotham <cauldwell.thomas_at_gmail.com>
Subject: [std-proposals] Use the exception system to check for bases at runtime

Use Case 1:


You have a variable of type std::any. You want to check if the contained value is derived from 'std::exception', and if it is, you want to return the 'what()' string. So you start off writing a function as follows:

    char const *get_what(std::any const &a)
    {
        void *const pderived = pointer_from_any(a);
        if ( nullptr == pderived ) return "<no info>";
        auto *const pbase = base<std::exception>( pderived, a.type() );
        if ( nullptr == pbase ) return "<no info>";
        return pbase->what();
    }

So first of all, we have an invocation of a function called "pointer_from_any" to get the address of the contained object, which on GNU g++ can be coded as follows:

    void *pointer_from_any(std::any const &a)
    {
        if ( false == a.has_value() ) return nullptr;

        auto const manager = (void (*)(int, std::any const*, void*)) *(void**)&a;

        void *retval;

        manager(0, &a, &retval);

        return retval;
    }

Next we have an invocation of a function called 'base', which is a template function with the following signature:

    template<class Base>
    Base *base(void *const parg, std::type_info const &ti);

You give this function two pieces of information:
    1) The address of an object (can be non-polymorphic or polymorphic)
    2) The type_info of the object

If the object has 'Base' as a base class, it returns a valid pointer to the base class. Otherwise it returns a nullptr.

I have coded 'base' to make use of the exception handling system. I looked at how GNU g++ implements 'make_exception_ptr' and 'rethrow_exception', and then I wrote the following function:

    template<class Base>
    Base *base(void *const parg, std::type_info const &ti)
    {
        using namespace __cxxabiv1;
        alignas(std::max_align_t) __cxa_refcounted_exception header = {}; // all zeroes
        char *pobj = static_cast<char*>(static_cast<void*>(&header + 1));
        header.referenceCount = 123;
        header.exc.exceptionType = const_cast<std::type_info*>(&ti);
        header.exc.exceptionDestructor = [](void*){};
        header.exc.unexpectedHandler =
reinterpret_cast<void(*)(void)>( std::get_terminate() );
        header.exc.terminateHandler = std::get_terminate();
        __GXX_INIT_PRIMARY_EXCEPTION_CLASS(header.exc.unwindHeader.exception_class);
        header.exc.unwindHeader.exception_cleanup = [](_Unwind_Reason_Code, _Unwind_Exception*){};

        try
        {
            std::rethrow_exception(
*static_cast<std::exception_ptr*>(static_cast<void*>(&pobj)) );
        }
        catch(Base &obj)
        {
            std::ptrdiff_t const delta = pobj - (char*)&obj;
            return (Base*)( (char*)parg - delta );
        }
        catch(...){}

        return nullptr;
    }

And so putting this altogether, what I'm peddling to you today is as follows:
    At runtime, if you give me the address of an object along with its type_info, I can confirm for you if any given class is one of its base classes, and if it is, I'll give you a pointer to the base class. The pointer will be appropriately adjusted in cases of multiple inheritance.

Here it is working up on GodBolt with GNU g++, LLVM clang++, and Intel ICX:

    https://godbolt.org/z/hvMr5WTK8

I'm hoping it can be coded for Microsoft too.

So a future standard of C++ could have the standalone template function 'base', and also the class 'std::any' could have a member function called 'base'.
--
Std-Proposals mailing list
Std-Proposals_at_[hidden]
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2024-04-02 16:35:39