Using Modern C++ to Eliminate Virtual Functions - Jonathan Gopel - CppCon 2022

preview_player
Показать описание
---

Using Modern C++ to Eliminate Virtual Functions - Jonathan Gopel - CppCon 2022

As of C++20, there are no cases in which statically linked programs require virtual functions. This talk will explore techniques for replacing runtime polymorphism with compile-time polymorphism such that virtual functions are never necessary. This talk will also address the higher-order concern of when it might make sense to avoid virtual functions or remove them from a codebase, as that decision ultimately is a design decision that only the author of the code can make. Attendees can expect to come away with a stronger understanding of the purposes of virtual functions and the mechanisms in modern C++ that can now be used to achieve those same purposes.
---

Jonathan Gopel

Jonathan is a C++ enthusiast who likes to tinker with the latest language features. He spends a lot of time thinking about designing beautiful, easy to use APIs, and believes that the hard part is interfacing with the humans, not the machines. In his spare time, Jonathan pursues outdoor sports - especially climbing, skiing, and running.
---

#cppcon #programming #functions
Рекомендации по теме
Комментарии
Автор

great talk by a knowledgeable speaker. I found the colors on the slides difficult to make out however, until I was blowing my retinas out with the white background

treyquattro
Автор

Interestingly enough I implemented something almost identical to this (although not quite as clean) in my codebase before discovering this talk. I can vouch that, for my application (massively parallel fluid simulation), there were performance benefits over std::variant that made it worth it, and the implementation is nothing crazy.

williamvannoordt
Автор

If you have tuple<vector<Ts>...> and need stable iteration, you can use tuple<vector<pair<INT, Ts>>...> where the INT in each pair represents the vector to look into next (this type INT needs to hold the number of vectors, i.e. needs not be size_t; for < 256 vectors, std::uint8_t is fine). The manager must keep track of the last vector (store 1 INT each) that was inserted into, so that its last value’s INT component can be updated when another element is inserted. It does not have to track the whole element, because insertion order in a vector _is_ stable. When iterating, one must keep track of the next element in each vector.

Bolpat
Автор

I 100% agree with the "bold statement" - you don't need to use virtual, you don't need to use smart pointers. I used that methodology in my c++20 order book project, which I talk about on my channel

soniakolasinska
Автор

Virtual function performance is often dependent on the compiler to determine if a call is really virtual or not. But on mature CPUs you also have branch prediction, so a virtual function will have zero performance overhead if and only if the CPU can perfectly predict the destination address. On tiny embedded cpus that might be an issue. I agree that a programmer always have to consider if a virtual function is needed or not.

chrisminnoy
Автор

For me, the only good use cases for virtual functions are: (1) having a container that can hold multiple implementations of the same base class and (2) decoupling implementations to have more unit-testable code. Variants or tuples of containers are sometimes a good alternative for case 1. However, there is no really good replacement for case 2. that does not involve some level of indirection.

Also, I should remind people here that the main cost of virtual functions is the fact that they are hard to inline. Their overhead is comparable to normal non-inlined functions, and usually, people mistake the overhead of virtual functions for the overhead incurred by the fact that they allocated their polymorphic objects on the heap.

broken_abi
Автор

Thanks for the talk. Very interesting.

I would only use this when it has a significant impact on performance in an area where it matters. It looks quite convoluted. I'd pick it over SFINAE every day though 😝.

bunpasi
Автор

it would have been good to have some data showing performance differences using this method. While I think the subject and talk is very interesting, I remain skeptical about the performance gains.

treyquattro
Автор

That tuple of vectors good idea but need to see in practice

stavb
Автор

Meantime while CPP 20 becomes mainstream (10 years or so), we can use the CRTP (Curiously Recurring Template Pattern ) pattern that has been around for a long to create static interfaces, unless CPP 20 is covering something else that CRTP can not.

fjrg
Автор

- It is very convoluted and therefore error-prone
- It requires lot of boiler-plate
- You need to know all the types at compile time to create an instance e.g., "Foo<Foo1, Foo2, ...>". Virtual inheritance allows run-time selection e.g., Base *base = Base::New("Derived")

sj
Автор

Good presentation on concepts. BUT you don't need unique_ptr / shared_ptr to call virtual functions. They can be stack allocated a passed around as references. In that case with a final keyword it compiler will most likely devirtualize and you write simpler code. Also why would you define all other constructors/operators if you pass-around the type as a pointer/reference.

I would say :
1. You want to represent a value. Use variant for polymorphism when you need it.
2. You want to represent a API to achieve something go for virtuals ;)

I you design the API well the virtual call cost is negligible.

janhruby
Автор

Great talk!

Why do you use
auto update() -> void {
and not
void update() {

?

Kolsha
Автор

How did we ended up making the syntax even more complex...

benjamin_fdw
Автор

30:00 downsides is missing a point.
Need to know fixed list of types at the time where you place the container that will store your things.
That means if a 3rd party wants to extend your code in the future, they have no option other than modifying/patching your code.
Where-as with virtual, it wouldn't matter as you just insert a pointer to the base class.

DedmenMiller
Автор

The overusage of "foo" makes this hard to follow

KillerMZE
Автор

Could you please provide accurate subtitles for this video?

player-eric
Автор

cpp people are working so hard to improve the language so much so, it is getting overwhelming ... "mental exercise" :)

Ptr-NG
Автор

Ok, I came to this because my daytime job is mostly Java, where every non-static method is virtual, and I was trying to see how this would work out. I have to admit our class hierarchies potentially grow deep and wide. It is a lot of behavioral inheritance with abstract methods as placeholders for different variations of behavior depending on where in the hierarchy you are. Somehow I fail to make the connection with this talk. I am guessing your usage of class hierarchies is simply to achieve different goals than we do. So far you seem to say that "if you don't need virtual you can get quite far without it" as well as "concepts can do neat things." That last one is definitely a takeaway for me...

BertLaverman
Автор

I kinda wanted to see if we can make interfaces without virtuals and templates.
If you create an interface with template, most of the code ends up becoming template.

WonbinKang-dp