Hacker News new | past | comments | ask | show | jobs | submit login

I have been told multiple times by C++ advocates, that C++ (whatever year is latest) doesn't have memory management issues... Is that not true?



Yes and no. You can write c++ code that handles memory in a safe and consistent way. Or you can write code which silently leaks and corrupts as it goes. The language doesn’t care and unfortunately even if you do everything correctly another programmer can mess with your allocated memory and silently break everything.


It can be pretty safe, but it requires restraint and selecting a good subset of the language. There's still plenty of footguns that an inexperienced person might hit.


And footguns that an experienced person might hit. One family of such footguns is:

    const auto &foo = something(args);
    …
    other_thing(foo);
Depending on exactly what you’re doing and what type something(args) returns, this can be entirely correct and idiomatic. In other circumstances it accesses a reference after its lifetime.

One can debate whether the const belongs there and how many &’s to use, but, unless something has changed dramatically in the last couple years (I’ve been focused on things that aren’t C++), there is no answer that is universally safe and efficient.


The temporary's reference is valid until the temporary is destroyed by falling out of scope, swapped etc. Or have I missed something?


The reference itself is indeed valid, in the sense of existing, until it falls out of scope. But the object it references may not be, so using the reference can be UB. Consider an std::vector v with length known to be at least 1:

    const auto &ref = v[0];
    v.push_back(42);
    cout << ref;
That works fine until push_back reallocates out of place, at which point you may start to notice that it’s actually UB.

Rust will not permit this problematic usage. GC languages tend not to offer this pattern — you can reference a boxed vector element with different semantics than the above C++ code, and you mostly can’t reference an unboxed element. C++ lets you do things like this but has little ability to statically verify correctness.

(Doing the above maneuver with a vector is a bit silly: it saves typing, and indexing a vector is extremely fast. With a map, though, indexing is not so fast, and keeping an iterator or a reference around may be a big performance win. At least if you keep an iterator around, dynamic checkers have a better chance of noticing errors.)


I think the point is just that unlike Rust there's no compiler enforcement that you only use refs in their lifetimes: you can easily accidentally cause a use after free.

Some times it can be pretty indirect: eg if the ref ends up pointing into some std container then it might need invalidated by making an otherwise unrelated change to the container.


Could you please explain this? I remember something about rvalues but it was as ages ago apparently :)


First time I've ever heard the term 'footgun'


It’s a reference to a decades-old quote from Bjarne Stroustrup, C++’s creator:

“In C++ it’s harder to shoot yourself in the foot, but when you do, you blow off your whole leg.”


It's not even so much that the footguns exist but that the consequence of hitting them is "undefined behavior" ie: anythign from core dump to reformatting your hard drive. Compare to Java where the consequence is one thing doesnt work right and someone has to debug it. Rarely it takes down a whole server side process but even then you get a lot of instrumentation and diagnostics to manage it and / or figure out what happened.


C++ is a nightmare language but this specific complaint is completely overblown. The compiler isn't going to format your hard drive (I know that one blog post exists - that is a deliberately constructed example).

A C++ program with UB is just buggy. Same as a java program with bugs. The program does something you don't want it to do. That's what a bug is. The compiler isn't going to maliciously introduce code that you didn't write to order pizzas.


I think there is a factor of UB that makes it have a steeper learning curve than the corresponding issues in other languages: with Java a lot of that category of bad code will throw exceptions and you'll get useful stack traces. UB often results in some seemingly nonsensical runtime state (eg something being null immediately after a null check, or a null dereference only leading to a segfault later in a place that locally has no pointers).

Compare mutating a container in a way that invalidates a live iterator: in java it's a specific exception that you can read on stack overflow, and in C++ it's just a use after free that might still appear to work correctly a random percentage of the time.


It's not that true... newer c++ features did go a long way in reducing memory management bugs but there's still a ton of footguns.


That greatly depends on use case.

I think if you're looking to write a simple HTTP server with some API functions that talk to some RDBMS at less than 100 requests per second, yeah, C++ is pretty hygienic and safe these days.

If you need to play around with memory management strategies like non-default allocators then yeah, the knives are still very sharp and will cut you if you're not careful. This comes up a lot when writing C++ extensions for scripting languages like PHP, Python, etc and you have to interact with objects managed outside of your C++ code.


> C++ is pretty hygienic and safe these days.

C++ these days still supports all the syntax and programming style of C++ in the 70s. You probably mean "you can program in a hygienic and safe way in C++", which is true, but also is not necessarily a feature of the language but of the programmer (just a few years ago I interacted with some theoretically senior C++ programmers who claimed mixing raw pointers with smart pointers is fine because they're senior and know what they're doing).


> C++ is pretty hygienic and safe these days.

Ask developers to safely define a string constant that is accessible outside of that translation unit. Now do it without C++17, which many companies aren't using yet.

Things have gotten a lot better, but even these incredibly basic needs can be really tricky.


Leaving aside the hyperbolic fringe, I'd guess that what you've heard is that it's possible for a team with discipline and experience to develop in such a way that they sidestep C++'s memory pitfalls. The situation being discussed here is the exact opposite.

For example, while I'm not particularly fond of Python as an engineering language, I've never worked on a team with poor enough process that we deal with (eg) production runtime failures due to typo-ed variable names that would have been caught by the compiler. And yet I'd never claim that it's impossible for such a problem to exist, given arbitrary levels of talent composed in arbitrary teams and processes.


Does a 911 with traction control off handle well? Definitely. Would you give the keys to someone who’s just passed their test? Definitely not


It's not true. Go look at security advisories that mention "buffer overflow".




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: