1

I want to do automatic cleanup using std::unique_ptr but to initialize the unique_ptr I need an address to point to. How can I avoid the noUse variable?

bool noUse;
auto deleter = [](bool *){ DESTROY_SOMETHING }; 
std::unique_ptr<bool, decltype(deleter)> upp(&noUse, deleter); // I want to avoid the usage of this extra noUse variable
START_SOMETHING

//COMPLEX IF ELSE RETURN LOGIC

**UPDATE: ** I finally resorted to this code. Thanks everyone for quick responses.

auto deleter = [](void *){ DESTROY_SOMETHING };
std::unique_ptr<void, decltype(deleter)> upp(nullptr, deleter);

if(enabled)
{
   //START_SOMETHING
   upp.reset(reinterpret_cast<void *>&upp);
}

//COMPLEX IF ELSE RETURN LOGIC

Mohit
  • 1,859
  • 1
  • 16
  • 25
  • what is `SOMETHING`? How does `deleter` delete something? – 463035818_is_not_an_ai Jul 05 '23 at 12:38
  • 3
    Does this answer your question? [Simple way to execute code at the end of function scope](https://stackoverflow.com/questions/50182244/simple-way-to-execute-code-at-the-end-of-function-scope) – Jan Schultke Jul 05 '23 at 12:46
  • 3
    Don't abuse `std::unique_ptr`. – Evg Jul 05 '23 at 13:17
  • Once I wrote my own `ScopeGuard` for some project, and then decided it's just not worth the effort. Now I just use `std::shared_ptr scopeGuard` for this kind of scenarios. I think the name of the variable makes the intent clear. [demo](https://godbolt.org/z/bEW5Kavz6) – pptaszni Jul 05 '23 at 13:29
  • Note that you are much better off writing a something-wrapping-smart-pointer and reusing it than writing per-scope cleanup code. Even if that means there are multiple destructors that have to run in a scope. Sorry, ESPECIALLY if that means there are multiple destructors that have to run in a scope. Because the compiler will keep track of which cleanup code to run if an exception occurs partway through the initialization. – Ben Voigt Jul 05 '23 at 14:28
  • Can you explain why you need to avoid an extra variable? – Brian Bi Jul 05 '23 at 22:35
  • 1
    If you make the deleter take `void*` (and use `unique_ptr`), then you can pass `&deleter` itself as the pointer value, or even `&upp`. – Brian Bi Jul 05 '23 at 22:40

1 Answers1

0

As long as the custom deleter doesn't require noUse to have any specific value, you can use some arbitrary integer literal (other than zero, that would make it a null pointer):

auto deleter = [](bool *){ DESTROY_SOMETHING };

// slightly longer but more robust:          reinterpret_cast<bool*>(&upp)
std::unique_ptr<bool, decltype(deleter)> upp(reinterpret_cast<bool*>(1), deleter);
// ...

This is a bit of a hack, and there are better solutions, such as std::experimental::scope_exit. It also doesn't make much sense that this is using a bool*, why not just a void* if we don't care about the type?

You can also build your own solution, see:

@Joe has written a solution very similar to std::experimental::scope_exit which does this.


Note 1: conversion of 1 to bool* has implementation-defined effect ([expr.reinterpret_cast]), using this pointer is implementation-defined ([basic.stc.general]), and comparison of the pointer to nullptr is implementation-defined, though never UB ([expr.eq]).

Note 2: Developers commonly create a local static variable and take its address when they need a std::unique_ptr as a "scope exit object". This is the most robust option.

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96