taocpp / taopq

C++ client library for PostgreSQL
Boost Software License 1.0
265 stars 40 forks source link

Allow compilation with `-fno-rtti` #44

Closed mattfbacon closed 3 years ago

mattfbacon commented 3 years ago

Using typeid doesn't seem to work even if the result can (and is) evaluated at compile-time. Specifically, typeid(int) or similar results in a compilation error.

Since this data is only used to make better error messages, and therefore is not crucial, replace the type string with "(no rtti)" when RTTI is disabled.

d-frey commented 3 years ago

Thanks for the suggestion. As you can see, I committed a different approach: We don't need RTTI anymore, but we can still demangle the types :)

mattfbacon commented 3 years ago

I saw some information about this but it seemed really complicated. I'm glad you did this because it will be helpful in my project with RTTI disabled.

d-frey commented 3 years ago

I never had a use-case for disabling RTTI, and I was under the impression that people that want/have to disable RTTI usually also can't use exceptions. So, first of all I'm happy it helped you, but I'm also curious: What environment allows exceptions but no RTTI?

mattfbacon commented 3 years ago

It's not that they're allowed or not per se. I just don't like the overhead that RTTI incurs. IIRC (and I'm not very sure because there's not much info), RTTI adds a vtable pointer to every object. I never use RTTI—in fact, I think it is squarely against proper OOP principles—so I have no reason to incur this overhead.

d-frey commented 3 years ago

The overhead of RTTI is generally very small, as it adds a pointer to the vtable if and only if the class already has a vtable. Classes without a vtable won't get one just because you enabled RTTI. There will be a typeid-structure (mostly the (mangled) name) for every class, but the compiler simply references this statically without dynamic lookup for non-virtual classes, so no vtable is needed/added in that case. And the vtable for virtual classes is shared between all objects of that class, meaning there is no per-object overhead added by RTTI, only a per-class overhead.

mattfbacon commented 3 years ago

Alright, that's good to know. I'm not sure why I couldn't find that information online. Seems like an implementation detail.

On the other hand, does it increase the size of the binary?

d-frey commented 3 years ago

It does increase the binary size, but again it's not a big difference in my experience. I just ran a small experiment on a binary from the PEGTL: With RTTI, it was 179376 bytes long, with -fno-rtti it went down to 179064 bytes on my system. GCC 11, -O3. (abnf2pegtl from the examples)

mattfbacon commented 3 years ago

Interesting. Thanks.

d-frey commented 3 years ago

And there is a problem: std::shared_ptr requires RTTI support, at least when you use std::get_deleter - which our connection pool does. See https://stackoverflow.com/questions/38180899/shared-ptr-without-rtti

So without RTTI-support the connection pool can not be used. II'll take care of it maybe tomorrow, for today I'm too tired.

mattfbacon commented 3 years ago

Forget it. I'll just enable RTTI. I thought this was much simpler than it is. I don't want to waste your time.

mattfbacon commented 3 years ago

https://en.cppreference.com/w/cpp/memory/shared_ptr/get_deleter

Compiling the example with -fno-rtti, get_deleter doesn't work, but the proper destructor is called. However, do you alias the shared_ptr? If not, why is it necessary.

mattfbacon commented 3 years ago

I'm confused. In https://en.cppreference.com/w/cpp/memory/shared_ptr, they say that the control block includes the deleter, but if that were true then why is RTTI required at all? Can't get_deleter just fetch the deleter from the control block?

d-frey commented 3 years ago

It's explained in the StackOverflow link I posted. It would be possible to implement get_deleter without RTTI, but it wasn't done and now it would break the ABI.

mattfbacon commented 3 years ago

Ah. Unfortunate. Anyway, I've enabled RTTI. I didn't used connection pool in the first place so there were no assertions that failed, but nonetheless I will enable it.

That makes me curious though. Would it be possible to implement our own, similar but different version of shared_ptr, that doesn't use RTTI?

d-frey commented 3 years ago

That's possible, but I don't want to unnecessarily introduce types that resemble standard types. Remember the type gets exposed in our API, it's not just an implementation detail. I'll revert the changes to demangle and simply require RTTI. As mentioned earlier, I only encountered people so far that couldn't use both RTTI and exceptions. And our design simply relies on exceptions, I don't feel like changing that. So, RTTI it is 🤷🏻‍♂️