Bartłomiej Filipek writes about modern C++, covering language features, concurrency tools, initialization, and practical coding advice.
HN commenters cite it for concurrency tools in C++17 and later and for a pimpl idiom discussion, amid debates about C++ complexity.
So, what programmers wanted (yes, already before C++ got this) was what are called "destructive move semantics".
These assignment semantics work how real life works. If I give you this Rubik's Cube now you have the Rubik's Cube and I do not have it any more. This unlocks important optimisations for non-trivial objects which have associated resources, if I can give you a Rubik's Cube then we don't need to clone mine, give you the clone and then destroy my original which is potentially much more work.
C++ 98 didn't have such semantics, and it had this property called RAII which means when a local variable leaves scope we destroy any values in that variable. So if I have a block of code which makes a local Rubik's Cube and then the block ends the Rubik's Cube is destroyed, I wrote no code to do that it just happens.
Thus for compatibility, C++ got this terrible "C++ move" where when I give you a Rubik's Cube, I also make a new hollow Rubik's Cube which exists just to say "I'm not really a Rubik's Cube, sorry, that's gone" and this way, when the local variable goes out of scope the destruction code says "Oh, it's not really a Rubik's Cube, no need to do more work".
Yes, there is a whole book about initialization in C++: https://www.cppstories.com/2023/init-story-print/
For trivial objects, moving is not an improvement, the CPU can do less work if we just copy the object, and it may be easier to write code which doesn't act as though they were moved when in fact they were…
Sorry, I still don't get how it's different from C++, and my point wasn't about `auto` but rather about `std::vector v2`:
std::vector v2 (v1.begin() + 1, v1.begin() + 2);
> However, in the provided example, the Rust type checker can use the provided clue to narrow this down to an exact type
The Rust example is incomplete and its RHS by the time it gets to `.collect()` within the context of `iterator` has to be bound to a particular type of the context via `impl Iterator for <MyContext>`. This is pretty much the same thing as template argument deduction for class templates in C++17 [1][2], and in C++20 it got extended to generic concepts and constraints [3]:
#include <numeric>
#include <vector>
#include <iostream>
#include <concepts>
template <typename T>
requires std::integral<T> || std::floating_point<T>
constexpr auto avg(std::vector<T> const &v)
{
auto sum = std::accumulate(v.begin(), v.end(), 0.0);
return sum / v.size();
}
int main()
{
std::vector v
{ 1, 2, 3 };
std::cout << avg(v) << std::endl;
}
Note that nowhere in the snippet do I specify the type explicitly except for the container of type vector.
[1] https://en.cppreference.com/w/cpp/language/template_argument_deduction
[2] https://devblogs.microsoft.com/cppblog/how-to-use-class-template-argument-deduction/
[3] https://www.cppstories.com/2021/concepts-intro/
https://www.cppstories.com/2026/shared_mutex/#newer-concurrency-tools-in-c20-and-above
> Since C++17, the concurrency library has expanded significantly. We now have:
> ...
> safe memory reclamation mechanisms (RCU, hazard pointers in C++26)
> These tools focus mostly on thread lifetime, coordination, cancellation or lock-free programming.
> std::shared_mutex fills a different role.
> It is still a mutual-exclusion primitive, explicitly designed to protect a shared state with many readers and few writers. It does not compete with atomics, condition variables, or RCU.
What does it mean to say shared_mutex does not "compete" with atomics/CVs/RCU? There are many situations where RCU or other safe reclamation mechanism is a good replacement for state + shared_mutex. (And some situations where atomics are a decent replacement.)
It depends on what problem you are trying to solve, your programming style, and the size of your team.
I personally will avoid C++ if possible because it has too much complexity, too many "gotchas", and there are better choices available (Rust, Go, Ada, C, etc.).
Some people like C++ and that is fine. They can use it. I will use something else if at all possible.
https://en.wikipedia.org/wiki/Criticism_of_C%2B%2B
https://250bpm.com/blog:4/
A 275-page book about how initialization works in C++:
https://www.cppstories.com/2022/cpp-init-book/
Some of C++ features are great, as recently discussed on the Linux kernel mailing list. However for many of Cs usecases, they are not appropriate, like exceptions and RAII in embedded. Once you start disabling major features those 'power tools' become far less attractive. Also, to extend the metaphor, hand tools are usually obvious and easy to use while power tools can have very long manuals. See for example the 275 page book on just Initilisation in C++ [0].
[0] https://www.cppstories.com/2022/cpp-init-book/
Read through https://www.learncpp.com. You'll get a complete refresher on the language, but it will be using modern C++ stuff (modern in this case means C++17).
For C++20 and newer, honestly, the only big feature that I ever use is concepts, although I do also use the new struct initialization syntax[0].
[0]: https://www.cppstories.com/2021/designated-init-cpp20/