Hacker News new | ask | show | jobs
by fch42 752 days ago
The part in it that I don't understand is ...

Again, "traditionally", one could (ab)use C++ as "C with extras". And it wasn't uncommon, especially in resource constraint usecases, to do just that. C++ without STL or templates, or even C++ without new/delete.

This "is not C++", agree. Would a subset be enough for "using it like C-with-RAII" ?

Given the details and pitfalls the original author lists, I suspect not. It's not just C programmers who "do strange things" and make odd choices. The language itself though "lends itself to that". I've (had to) write code that sometimes-alloca'ed sometimes-malloc'ed the same thing and then "tagged" it to indicate whether it needed free() or "just" the implied drop. Another rather common antipattern is "generic embedded payloads" - the struct definition ending "char data[1]" just to be padded out by whatever creates it to whatever size (nevermind type) of that data.

Can you write _new_ C code that "does RAII" ? Probably. Just rewrite it in rust, or zig :-) Can you somehow transmogrify language, compiler, standard lib so that you can recompile existing C code, it not to "just get RAII" then at least to give you meaningful compiler errors/warnings that tell you how to change it ? I won't put money on that.

3 comments

New/delete were never that great to begin with and have now fallen out of style. Also, C++ is quite useful and powerful even without STL.

https://www.youtube.com/watch?v=rX0ItVEVjHc

A classic which touches on such stuff.

The STL is pretty dispensable in my experience, even for people doing full-blown modern C++, and C++20 has made that particularly obvious. The most useful feature somewhat unique to C++ is the extensive metaprogramming facility, which only recently became non-arcane.
> Can you write _new_ C code that "does RAII" ? Probably.

You can do "manual" goto-based RAII in C, and it has been done for decades. The end of your function needs to have a cascading layer of labels, undoing what has been done before:

    if (!(x = create_x())) {
        goto cleanup;
    }

    if (!(y = create_y())) {
        goto cleanup_x;
    }

    if (!(z = create_z())) {
        goto cleanup_y;
    }

    do_something(x, y, z);

    cleanup_z:
    destroy_z(z);
    cleanup_y:
    destroy_y(y);
    cleanup_x:
    destroy_x(x);
    cleanup:
    return;
It just takes more discipline and is more error-prone maintenance-wise.
That's not RAII, that's 'defer'. defer and context managers are both implementations of a subset of the kind of functionality you can get with RAII (the two missing parts are 1) allowing you to place an RAII object in part of a larger structure and have confidence it will actually be constructed and destructed correctly, and 2) allowing the representation of lifetimes which are more complex then just 'in this scope' via moves and copies).
except this misses the point of RAII.