On Wed, Jun 07, 2023 at 11:41:01AM +0200, Peter Zijlstra wrote: > > I'm sure there's something horribly wrong in the above, but my point > > is that I'd really like this to make naming and conceptual sense. > > Right, I hear ya. So the asymmetric case (iow destructor only) could be > seen as using the copy-constructor. > > #define DEFINE_CLASS(name, type, exit, init, init_args...) \ > typedef type class_##name##_t; \ > static inline void class_##name##_destructor(type *this) \ > { type THIS = *this; exit; } \ > static inline type class_##name##_constructor(init_args) \ > { type THIS = init; return THIS; } > > #define __INSTANTIATE_VAR(name, var) \ > class_##name##_t var __cleanup(class_##name##_destructor) > > #define INSTANTIATE_CLASS(name, var) \ > __INSTANTIATE_VAR(name, var) = class_##name##_constructor > > > DEFINE_CLASS(fd, struct fd, fdput(THIS), f, struct fd f) > > INSTANTIATE_CLASS(fd, f)(perf_fget_light(fd)); > > > Alternatively, you be OK with exposing INSTANTIATE_VAR() to easily > circumvent the default constructor? Or perhaps use the smart-pointer concept applied to our classes like: #define smart_ptr(name, var) \ __INSTANTIATE_VAR(name, var) To mean a pointer that calls the destructor for class 'name'. I think the nearest thing C++ has is std::unique_ptr<>. Then we can write: DEFINE_CLASS(kfree, void *, kfree(THIS), p, void *p) smart_ptr(kfree, mem) = kzalloc_node(...); if (!mem) return -ENOMEM; object = mem; // further initiatlize object with error cases etc.. mem = NULL; // success, we keep it. return object;