I'm completely ignorant about C++, so I will ask this question: What's the state of memory management in modern C++? Is it easier to avoid shooting yourself in the foot? Can you write code that is completely safe?
I've always flat-out avoided C++ because I don't think I will be able to handle memory management for a large program; It'll be riddled with security holes and memory leaks.
Unfortunately, many OSS programs I want to contribute to are written in unmanaged languages like C or C++. As far as I'm aware, it's easier to get memory right in modern C++ compared to C, which hasn't received many updates.
No. The modern C++ features like std::unique_ptr and std::shared_ptr replace old patterns of "malloc()/free()" and "new/delete". This ensures correct cleanup and avoids leaking memory.
However, there are other topics of "memory safety" such as preventing runtime behavior of buffer overruns and writing to invalid pointers. The virtual machines like Java JVM and C# CLR create a constrained memory area with extra runtime checks and the new C++ language features don't replicate that type of memory safety. Also, those "managed" languages don't expose raw pointers as a 1st class programming feature (e.g. don't use "unsafe" blocks) so that in itself creates an environment of extra memory safety.
"This ensures correct cleanup and avoids leaking memory."
Although shared_ptr does open you up to a whole new class of bugs, with circular references causing memory leaks and object lifetimes being harder to reason about, especially in a multi-threaded environment.
I agree in general, though, things are a lot better.
> I'm completely ignorant about C++, so I will ask this question: What's the state of memory management in modern C++? Is it easier to avoid shooting yourself in the foot? Can you write code that is completely safe?
I would not say completely safe if we only consider the language, but on the rare occurence of a memory bug, usage of asan / ubsan of GCC and Clang (both have different sets of checkers), -D_GLIBCXX_DEBUG and clang-tidy, it's frankly impossible to have this kind of bugs. Just running by default with -fsanitize=address -fsanitize=undefined will help you to trivially eliminate so many bugs it's not even funny.
However, you fight the language much less than in Rust in my experience, and if you don't do memory allocations directly but instead use <vector> and others it will be a breeze.
While it's true that processor flaws destroy the assumptions that higher level components (such as any/all programming languages) build on, you don't need to go nearly that far to see unsafety in C++, even using only the most modern techniques: use-after-move of many types is undefined behaviour (for instance, dereferencing a std::unique_ptr that has been moved from), and iterator invalidation & dangling references aren't addressed by those smart pointers at all.
I've always flat-out avoided C++ because I don't think I will be able to handle memory management for a large program; It'll be riddled with security holes and memory leaks.
Unfortunately, many OSS programs I want to contribute to are written in unmanaged languages like C or C++. As far as I'm aware, it's easier to get memory right in modern C++ compared to C, which hasn't received many updates.