If the compiler checks that you do it, sure.
For local variables, I'd say `defer` is an okay but not great substitute. If you call malloc() yourself, then sure, it's not hard to remember to stick a "defer { free(ptr); }" afterwards. But what if you call a function that returns an owned value? Can you tell just from looking at it that you're meant to free the thing afterward?
CoreFoundation, a C library on Apple platforms, has a cute solution to this: a strict naming convention. [1] If a function returns a value at "+1" reference count, i.e. you have to release it yourself, the function's name should include "Create" or "Copy", even where that would otherwise seem unnatural. For example, "CFSocketCopyAddress" returns a socket's address as a CFDataRef, returned at +1. You might expect it to be called "CFSocketGetAddress", but "Get" is reserved for functions that return values at +0.
As I said, cute – but fundamentally a workaround for language limitations. Distinguishing between two kinds of functions is exactly the sort of menial bookkeeping that computers excel at, whereas humans are prone to making mistakes. And – while CoreFoundation is forever stuck with the goal of C compatibility, Objective-C, which used to rely on a very similar system of manual retain/release and naming conventions, did ultimately transition to automatic reference counting.
But it doesn't have to be automatic. One use for destructors is to automatically release locks, and an interesting alternative design for that exists in Clang's "thread safety" annotations. These are annotations you can add to existing C or C++ code that uses mutexes; their main purpose is to catch you if you access a variable protected by a mutex without owning the mutex, but they can also complain if you lock something and forgot to unlock it. You can annotate functions as "requires mutex" (i.e. you must call it with the mutex locked, and it stays locked after the function), "acquire" (call with it unlocked, returns with it locked), "release" (the opposite), and so on. I think I once tried to abuse the annotation system to enforce reference counting, but it was broken. But I'd love to see a more thorough and robust design along these lines.
[1] https://developer.apple.com/library/archive/documentation/Co...