News for hackers. Stuff that matters.
Re:Building a Cloud Database from Scratch: Why We Moved from... by flohofwoe on Saturday May 28, 2022 @03:20AM (#31538298)
Now I'm curious, where's the leak?

...assuming that there's a matching free_mem(ptr, n) which undoes the actions of get_mem() of course. Also I'm ignoring the cofusing use of auto vs auto*, I haven't caught up with modern C++ enough to know whether this even makes sense ;)

...also, what would the better RAII version of this function look like?

Re:Building a Cloud Database from Scratch: Why We Moved from... by varajelle on Saturday May 28, 2022 @04:16AM (#31538566)
Maybe he is talking about exception safety. vector::push_back could throw an exception.

But this is far fetched because people doing manual memory management don't usually rely on exceptions, and just abort the program when this happens, so the leak is pointless.

Re:Building a Cloud Database from Scratch: Why We Moved from... by jcelerier on Saturday May 28, 2022 @04:31AM (#31538635)
> But this is far fetched because people doing manual memory management don't usually rely on exceptions,

I think you really, really underestimate the amount of codebases where a large part of the code is "normal" C++ with exceptions and someone does one specific module with manual malloc / free out of cargo-culting some RAII fears.

Hell, even OP above talks about using vector along with their custom memory management scheme (which throws no matter if you use -fno-exceptions or not, as the actual "throw" call is in the precompiled libc++.so ; the code in <vector> just calls std::__throw_bad_array_new_length() indiscriminately : https://gcc.godbolt.org/z/fno8fYP7E )

Re:Building a Cloud Database from Scratch: Why We Moved from... by flohofwoe on Sunday May 29, 2022 @05:12AM (#31547685)
But with -fno-exceptions all exceptions cause a panic which stops execution of the program, right? So technically not a leak ;) (but TBH: exceptions don't even enter my mind anymore in the context of C++ because I had switched them off since I started C++ coding in the late 90's, I just don't see the value of exceptions in systems programming language, there's just too much compiler magic involved to make them work).

I think the actual problem is that std::vector is doing its own memory management under the hood, which makes it hard to control what's going on from the outside. E.g. a design flaw of the C++ stdlib, not related to RAII.

Re:Building a Cloud Database from Scratch: Why We Moved from... by jcelerier on Sunday May 29, 2022 @08:51AM (#31548753)
> But with -fno-exceptions all exceptions cause a panic which stops execution of the program, right?

plenty of cases where this isn't the case.

-fno-exceptions just means that you want to not be able to throw for your own code.

-fno-unwind-tables / -fno-asynchronous-unwind-tables makes your own code un-unwindable which is only safe if you are in entire control of the whole codebase, which is very rare in anything that is not simple games - no plug-in system, or any dynamic code loading or JIT'ing is safe as you don't know which user-provided function you call is going to throw.

Likewise, you could be in the opposite case: imagine you're making a C++ plug-in for, say, 3DS Max, where error reporting is done through exceptions ; even if your own plug-in code is built with -fno-exceptions and does not itself throw at any point, you still want exceptions that may be coming from a 3DSMax function you called to propagate to your code back to the exception handler provided by 3DS Max - and for this RAII of your own types is needed if you don't want your own resources to be leaked.

Re:Building a Cloud Database from Scratch: Why We Moved from... by jcelerier on Saturday May 28, 2022 @04:10AM (#31538528)
auto* is just to indicate to the reader that your_malloc for sure returns a raw pointer and not some RAII type already.

std::vector::push_back can throw an exception, if for instance you just allocated 2 gigabytes of memory before and it does not have space to reallocate its internal storage:

    std::vector<int> allocation_counts;

    auto get_mem(int n) { 
      auto* memory = your_malloc(n);

      // if this throws: the function exits there and "memory" is lost forever
      allocation_counts.push_back(n); 

      return memory;
    }

A simple way to "RAII-fy" it would be, assuming a `your_free`:

    // Typedef this somewhere
    using your_ptr = std::unique_ptr<void, decltype([] (auto p) { your_free(p); })>;      

    auto get_mem(int n) { 
      // encapsulate in your_ptr
      auto memory = your_ptr{your_malloc(n)};

      // if this throws: memory's destructor is called which frees the memory
      allocation_counts.push_back(n);

      return memory;
    }
Or if you want your custom RAII type for some reason:

    // memory.h or something
    struct mem {
      mem() = default;

      // copy is not meaningful here
      mem(const mem&) = delete;
      mem& operator=(const mem&) = delete;

      // move
      mem(mem&& other): ptr{std::exchange(other.ptr, nullptr)} { }
      mem& operator=(mem&& other) { ptr = std::exchange(other.ptr, nullptr); return *this; }

      // allocation & deallocation
      explicit mem(int n): ptr{your_malloc(n)} { }
      ~mem() { your_free(ptr); }

      void* ptr{};
    };

    // your code
    std::vector<int> allocation_counts;
    auto get_mem(int n) { 
      auto memory = mem{n};

      // if this throws: mem's destructor is called which frees the memory
      allocation_counts.push_back(n);

      return memory;
    }