Back to Basics: Cpp Value Semantics - Klaus Iglberger - CppCon 2022

แชร์
ฝัง

ความคิดเห็น • 33

  • @thelatestartosrs
    @thelatestartosrs ปีที่แล้ว +5

    One disadvantage of variant is it takes size slightly greater than its largest type, so if one shape is complex but appears rarely, too bad, your vector of shape variants will allocate more than a vector of that largest type. I don't think its a very compromising issue but still its good to know.

    • @joshhoover1202
      @joshhoover1202 ปีที่แล้ว +6

      Another note is that if you go down the route of using a vector of unique_ptr and memory fragmentation is a problem you can use pools from std::pmr to reduce the fragmentation.

    • @tourdesource
      @tourdesource ปีที่แล้ว

      @@joshhoover1202 Interesting info, thanks for sharing

    • @binary132
      @binary132 7 หลายเดือนก่อน

      This can actually be a big problem in AST parsers where some token types can represent large, complex nested expressions. Zig has an implementation of something called MultiArrayList which abstracts over a different backing store for each member type.
      th-cam.com/video/UCvASZT7ELU/w-d-xo.html

    • @theronerdithas2944
      @theronerdithas2944 2 หลายเดือนก่อน

      @@thelatestartosrs if one or so of the elements are much larger and more rare than the rest, then just put a pointer to it's type in the variant.

  • @9uiop
    @9uiop ปีที่แล้ว +25

    Klaus is a great presenter, I've enjoyed this talk a lot as always.

    • @truyenyyreview
      @truyenyyreview ปีที่แล้ว

      Yes me too, wish I have chance to attend his live CppCon.

  • @andreysolovyev630
    @andreysolovyev630 ปีที่แล้ว +2

    Thank you very much for the great presentation.
    May I offer another point of view on a trade off between value semantics and pointers?
    You can overview a class called ObjectHolder that contains different objects. Please compare such a class designed on variant and on unique_ptr. Here you (or anybody) will bump into all sorts of problems - slicing, object hold actual type determining, type casting problems, overheads in using dynamic_cast , etc, etc.
    Review of such problems and the way of tackling them may be useful for audience.

  • @kimhyunpil
    @kimhyunpil ปีที่แล้ว

    brilliant talk!

  • @AbelShields
    @AbelShields ปีที่แล้ว +4

    23:17 - this is why people love Rust, it takes care of this sort of stuff for you. You don't need to worry about a reference going invalid when a vector resizes, or a tree is balanced, it tells you what you're doing wrong and where.

    • @roykin0929
      @roykin0929 ปีที่แล้ว

      How would rust take care of this if we write an equivalent code in rust?
      Not hating or anything, I'm just curious

    • @joshhoover1202
      @joshhoover1202 ปีที่แล้ว +2

      @@roykin0929 It uses a borrow checker as a part of the compiler. The idea is that if you made a span of a vector it would have borrowed the vector and then reassigning to the vector in a way that could invalidate the span would be disallowed until the span no longer existed.

  • @DotcomL
    @DotcomL ปีที่แล้ว +1

    I did get a bit curious on how you would finish the command pattern using std::function and value semantics

  • @HomerSimpson900
    @HomerSimpson900 ปีที่แล้ว +1

    Well presented. I'd like some questioning of just how variant beats virtuals and classic visitor. One advantage of visitor is that downstream projects can hook in their own custom types. Seems like variant, because it bakes in a finite number of compile-time cases (shapes) cannot allow this extensibility. Is that fundamentally why the performance gain with variant is possible?

    • @Adowrath
      @Adowrath ปีที่แล้ว

      How would you extend the available types in the Visitor pattern without changing the original definitions, though? If for the shape example, you add let's say Octagon, that'd necessitate a visitOctagon method on the Visitor, no? What would/should happen if I then take the Draw-visitor as defined in the talk, and try to use it with said Octagon?

    • @adfriedman
      @adfriedman ปีที่แล้ว +2

      As he alluded to in the Q/A, the visitor pattern is used to allow extension of behavior given a fixed set of types, it's not meant to hook in custom types (like new shapes). The only way you'd be able to add custom shape types to the inheritance-based visitor pattern is by adding other visit(...) implementations by modifying the base class ShapeVisitor and all derived classes like Draw and Rotate. This would violate the Open/Closed principle and requires recompiling the base class, so it probably isn't the pattern you want if you are planning to add shapes (using inheritance or otherwise).

  • @flocela
    @flocela ปีที่แล้ว

    kids play outside --- ha ha ha ! : )

  • @AxWarhawk
    @AxWarhawk ปีที่แล้ว +6

    15:52 While I agree with the bullets listed, aren't we violating the Open-Close Principle here?!
    Assuming the original hierarchy-based architecture, one can define their own shapes and extend the visitor to also cover those shapes without modifying the original code. With the variant approach, the variant needs to be changed to account for newly added shapes. It follows that all code using the variant now needs to be updated to account for the new shapes. Furthermore, this might not be possible if the definition resides in a library which you can't modify.
    While this approach looks a lot simpler, I feel like it contradicts Klaus' previous talks Designing Classes.

    • @klausiglberger566
      @klausiglberger566 ปีที่แล้ว +18

      You are correct: with regard to adding new shape types, this approach violates the OCP. Hence if your goal is to extend the number of shape types, you should neither use the classic Visitor, nor the modern std::variant approach. Instead you should take a look at Type Erasure (see for instance my CppCon 2021 talk about that topic).
      The intent of the Visitor design pattern and its modern form std::variant is to enable you to easily add new operations, not types. So with regard to adding operations, Visitor/variant follows the OCP. The choice which kind of extension you need is a fundamental choice you'll always have to make when design software with dynamic polymorphism: do you want to add types or operations. Based on that decision, one kind of extension will be simple, the other one will be difficult.
      I've explained this point in detail in my book "C++ Software Design" (www.oreilly.com/library/view/c-software-design/9781098113155/). In particular, please take a look at Guideline 15 ("Design for the Addition of Types or Operations").

    • @AxWarhawk
      @AxWarhawk ปีที่แล้ว

      @@klausiglberger566 Thanks for the detailed answer. And thanks for the talk, of course.

  • @张洋-s4r
    @张洋-s4r 20 วันที่ผ่านมา

    Is std:variant like zig's tagged union?

  • @robert-yates
    @robert-yates ปีที่แล้ว +4

    it's always a pleasure to listen to klaus' talks

  • @HellCatLeMaudit
    @HellCatLeMaudit ปีที่แล้ว +1

    My problem with strict object oriented programming is that I need to rotate a polygon but before I can do that I need to think of its inheritance first and build things I don't really need at all. Real life programming is not like academic programming where we can take the time to create principles and implement those principles so we can write a paper about it.
    Non-academic programming requires that I get that software prototype out the door yesterday. Most first versions of software get thrown away after all. We learn something from our experience and the second version will incorporate those experiences. Perhaps in the third iteration we can think about casting what we learned, the experiences, into a methodology, and get that structure poured in concrete. But not the first version!
    At least C++ allows me to program without classes first before committing myself or the team to a structure which will turn out to be useless but had to be used because time and resources were spent on it. I can't say the same about Java. Java is the reason IDEs have for existence. The taxonomy of the classes is so complex no one can keep it all in her head.

  • @bunpasi
    @bunpasi ปีที่แล้ว +2

    I'm always up for a talk of Klaus. His videos are so digestible.

  • @6fishoutofwater
    @6fishoutofwater ปีที่แล้ว +2

    Great talk Klaus! Very informative and well delivered.

  • @peregrin71
    @peregrin71 ปีที่แล้ว

    Don't underestimate Klaus's comments about value semantics in multithreaded and distributed systems. Using reference semantics in those situations is setting yourself up to fail. (If you think you need reference semantics in multithreaded environment then look at std::shared_ptr and pass that as value).

  • @tourdesource
    @tourdesource ปีที่แล้ว

    Why doesn't std::erase decrement the target pointers of its upcoming iterations since it knows it just removed one element from the container?

  • @dietmargrabowski7189
    @dietmargrabowski7189 ปีที่แล้ว

    Good talk, thank you

  • @mcmaddie
    @mcmaddie ปีที่แล้ว

    10:00 While value semantics looks good and are the 'new cool thing' I like the 'old' way. That capsulates everything of those shapes in one class. Now instead having everything about for example circle in one place you have the circle class and then you need to implement draw - function for it in another class. It's more of a maintenance point of view than performance. And yes I have GUI library that is implemented similarly to 'old' way so maybe that's why I'm biased towards it, but I like that component knows how to draw itself.

    • @AbelShields
      @AbelShields ปีที่แล้ว +1

      The only issue with that is it makes code less modular. What if someone wants to use a different graphics library? They can't just implement their own draw for each shape, they need to modify your code to add functionality.

    • @thelatestartosrs
      @thelatestartosrs ปีที่แล้ว +1

      the visitor pattern is literally about taking draw and moving it out of the "component" if you did as you said and your class Shape has a method draw its not a case of visitor vs value semantics as he is describing

    • @jimhewes7507
      @jimhewes7507 ปีที่แล้ว +1

      Another way would be to just add an abstraction layer over the graphics libraries themselves if possible. Then the shape objects don't need any library-specific code. However the libraries could be too different to do that. So I guess there is Strategy or Visitor.
      Using std::variant I need to query the variant which type is has every time I want to use it, true? Then isn't that as expensive as a virtual function call?
      Iglberger has other videos on Type Erasure. Though it seems you have to give up encapsulation for that. So for me, the jury's still out on that. I'd like it perhaps for situations where derived classes are inheriting too much. But often normal inheritance is easier.

  • @HellCatLeMaudit
    @HellCatLeMaudit ปีที่แล้ว +3

    Object oriented programming (or thinking in terms of classes and objects) became such a religion that even reasonable mathematicians convinced themselves that when we have two matrices A and B, then A + B means A adds itself to B (and thus modifying itself in the process) instead of the usual mathematical thinking of A + B being an operation on matrices A and B that results in a third matrix C.