← Back to context

Comment by Moldoteck

1 day ago

Is there a difference between c++ and java/go/etc if you enforce at code review for C++ to use only auto memory management like smart ptrs, containers, etc? I guess the only difference would be c++ can have diamond problem that's solved in a specific way, but that's relatively easy to spot with compilers, but otherwise...

Imo the strong point of rust is compile error if you try to use an obj after move (unlike c++ with undef behavior and I guess it should be the same for java/c#), or that you can't modify a container if you hold a ref/pointer to some of it's elements/range which may cause invalidation in C++ case due to realloc

Yes there is. RAII is not a full replacement for GC and you will shoot yourself in the foot if you treat it as such. The design of C++ also includes many unpatchable holes in the standard library which WILL cause errors and UB.

  • So how exactly would this shooting in the foot look like compared to say java

    • Too many to list, but for some examples:

      You take a reference to a vector element, which you later accidentally invalidate by pushing to the same vector.

      You move out of a unique_ptr, but then you accidentally use it again.

      You create a cycle with shared_ptr causing a memory leak.

      If you std::sort a list of floats with NaNs (among other things) you can stomp over memory. The sort function requires some very specific ordering otherwise you get UB.

      1 reply →

> Is there a difference between c++ and java/go/etc if you enforce at code review for C++ to use only auto memory management like smart ptrs, containers, etc?

Smart pointers and containers are nowhere near memory safe, just enforcing their use gets you nowhere. `std::vector::operator[](size_t)` doesn't check bounds, `std::unique_ptr::operator*()` doesn't check null.

> Imo the strong point of rust is compile error if you try to use an obj after move (unlike c++ with undef behavior

The state of a value after being moved is defined by the move constructor. It is unspecified by the spec, but it's generally not undefined behavior.

  • They do when using hardned runtimes configuration, which was compiler specific, and starting with C++26 is officially part of the standard.

    It naturally doesn't cover C style programming in C++.

  • What you mean by smart ptrs not being memory safe? Vector access can be done with at method

    • Which unfortunately most people avoid using, and until C++26 there is no at() for span.

      The best is really to enable compiler specific hardening.

Yes, because code review isn't common, it is at the same level as writing documentation, or unit tests in most companies.

Unless there is some DevOps freedom to at least put something like Sonar or clang tidy on the build pipeline breaking PR that don't play by the rules, and even then you cannot prevent everything via static analysis rules.

  • I think it's (mostly) sufficient to have a regex on git change-set for "new" "malloc" "calloc" keywords to cut most of such stuff if you have such a policy.

    Documentation / UT are harder to define (what is good documentation, is UT covering everything?), but usage of manual memory handling can be spotted relatively easy automatically. There can be some exceptions for 3rd party libs interaction if it's absolutely necessary but detecting such occurrences and keeping track of them is relatively easy.

    • See, already there you missed all the C language constructs that C++ is copy-paste compatible with, and should only be used inside unsafe code blocks.

      Which in C++ good practices means type safe abstractions not exposing any kind of C style strings, arrays, casts, pointer arithmetic,....

      Unfortunely still relatively rare, some of us when we were the C++ Striking Force in the 1990's Usenet flamewars already advocated for such practices, most of them already possible with C++ARM, no need for modern, post-modern, rococo, baroque or whatever C++ style is going on with C++26 now.