The Dark Side of C++ - Copy-On-Write
Вставка
- Опубліковано 3 лис 2024
- Copy-On-Write or lazy copy is a technique in C++ to avoid unnecessary copies. In this viedo I show how to implement copy-on-write using shared pointers.
Tools that I use:
www.virtualbox...
kubuntu.org/
code.visualstu...
llvm.org/
clang.org/
mesonbuild.com...
In code:
github.com/ren...
github.com/Zen...
github.com/oco...
github.com/epe...
I only knew COW from virtual memory pages. Haven't thought of using it in C++. What a great idea. Love it!
It's also worth thinking about if the underlying object is read often or not. Let's say that its read millions of times, before actually being changed; in those scenarios, it might be better to copy the object directly without wrapping it in this Cowptr and shared_ptr; because copying the object could be cheaper and faster than having to access the object through several layers of indirection each time, of those millions of reads (ie, accessing it through a T* instead)
But this is of course is a design question one would answer beforehand
You explained how to write a wrapper class.. but not WHEN or WHY to do this. It's not enough to just say "you'll get better performance". You need to add a lot more context for this video to actually help anyone. In what real-world scenario would you use this kind of wrapper, and how it is any different or better than just using a by-value or by-reference parameter as the argument to whatever function that you want to copy, or not copy, your object?
It is useful for data that is often read, but rarely written and expensive to copy. E.g. large config files, images, videos.
@@ZenSepiol Using copy-on-write in C++ can NUKE performance in some cases.
In your example, if we have a large configuration file and use copy-on-write, a simple operation that should be fast (O(1)) might suddenly become very slow because it needs to copy the configuration.
Instead, if we load the configuration into memory once and keep it there, we avoid copying during important operations. So, before using copy-on-write, decide what’s more important: saving memory or avoiding slow copy operations during execution.
Yep lazy, deferred code execution can be useful.
C++ is not the language that I work in very frequently (currently learning Rust, a truely amazing language I can recommend which solves a ton of C/C++'s caveats).
But I would say, if this COW solution for smart points is a actually good idea, then one day they will probably implement it in the standard libraries if it hasn't already been done it yet.
What I know is that in many languages, iterator patterns are generally lazilly constructed patterns. In C# we have IEnumerable / IEnumerator based code which is all lazy. And functional style code and is often built around those iterators.
Maybe the answer to lazy code lays actually there, in the way how you iterate on collections of objects, rather than in the individual objects their class implementations themselves.
So probably the need for lazy individual objects is not high enough.
Would love to see lazy execution more deeply embedded into languages. But I guess having it 100% bullet proof is really hard and building compilers for it surely will be tricky. Cow implementations are available in many popular libraries (e.g. boost, unreal …).
I want to take a look into rust for such a long time! It really looks promising. Also Carbon looks definitely interesting, but it is barely released and not yet battle tested.
If I recall correctly, using copy-on-write was an exploit to achieve privilege escalation in Linux while ago. Interesting to see its actual use cases.
Didn‘t know that, interesting fact!
COW is a very general concept. Advanced filesystems like ZFS and Btrfs are completely based on it. Although there we are talking about the concept applied to storage on drives, not just in running code inside RAM memory.
Regarding the code a possible exploit is a side-channel attack. E.g. if the execution time is data dependent (which for cow it actually is!) you can correlate the data with the execution time to extract the key. Back in college we used this to crack AES. Side-channel attacks are really powerful.
good stuff.
Starting from c++ 11 cow strings are forbidden. Standard string is faster and more MT friendly (move constructors) .
Starting c++ 14 std::string has a small string optimization !
Starting from c++ 17 compiler can perform guaranteed copy elisions!!
Dont use cow strings!
Dont use cow atall its obsolete
1. this is not really copy-on-write.. it's copy on non-const usage... so It's a significant pessimization
2. In line 54 of your example, you are using the old "cow_string" instead of "cow_string2". That's the only reason why, in line 55, .content was not copied. Fixing the example, line 54 will cause a copy. (see point 1)... basically negating the claims of your explanation
Thanks for the input!
You are right, it is copy on non-const usage. But I don't see the pessimization. Why would I want to have non-const functions which are not mutating the object? Const-correctness is important for performance.
You are also right regarding the example. To fix it and to get the proper behavior line 54 should use "*cow_string2.content" (not only *cow_string2). Using only *cow_string2 will result in a copy.
Yon need to use a teleprompter :)
😅