Unique_ptr and standard construct pointer

I recently tried to rethink area protection with std::unique_ptr ( NOTE : Deleter has a member of typedef pointer - this is a specially crafted case of std::unique_ptr ):

 #include <type_traits> #include <utility> #include <memory> #include <iostream> #include <cstdlib> #include <cassert> namespace { template< typename lambda > auto make_scope_guard(lambda && _lambda) { struct lambda_caller { using pointer = std::decay_t< lambda >; void operator () (lambda & l) const noexcept { std::forward< lambda >(l)(); } }; return std::unique_ptr< std::decay_t< lambda >, lambda_caller >(std::forward< lambda >(_lambda)); } } int main() { std::cout << 1 << std::endl; { std::cout << 2 << std::endl; [[gnu::unused]] auto && guard_ = make_scope_guard([&] { std::cout << __PRETTY_FUNCTION__ << std::endl; }); std::cout << 3 << std::endl; } std::cout << 5 << std::endl; return EXIT_SUCCESS; } 

This approach is great for a simple pointer to a free function void f() { std::cout << 4 << std::endl; } void f() { std::cout << 4 << std::endl; } passed to make_scope_guard , but not for any lambda passed to make_scope_guard .

This is due to the abundance of ... = pointer() in the definition of std::unique_ptr (default function parameter, default memebers data, etc.), but I cannot find the DefaultConstructible requirement for pointer in this article .

Is it mandatory that pointer must meet the requirement of std::is_default_constructible ?

It was tested against libc++ and against libstdc++ using the not-so-old clang++ -std=gnu++1z .

There seems to be a language extension for lambdas: if auto l = [/* possible capture list */] (Args...) { /* code */; }; auto l = [/* possible capture list */] (Args...) { /* code */; }; , then using L = decltype(l); equivalent to struct L { constexpr void operator () (Args...) const noexcept { ; } }; struct L { constexpr void operator () (Args...) const noexcept { ; } }; for some Args... right?

ADDITIONALLY:

Providing an instance of D{} following DefaultConstructible class for make_scope_guard(D{}) requires the comment code to be uncommented in the context of if (p) { ... , where p is of type D :

 struct D { void operator () () const noexcept { std::cout << __PRETTY_FUNCTION__ << std::endl; } /* constexpr operator bool () const { return true; } */ }; 
+5
source share
1 answer

A unique_ptr is still a pointer. You can't curb lambda. From [unique.ptr]:

A unique pointer is an object that owns another object and manages this other object using a pointer . More precisely, the only pointer is the u object that stores the pointer to the second object p and will recycle p when u itself is destroyed

[...]

In addition, you can, upon request, transfer ownership to another unique index u2. Upon completion of such a transfer, the following post-conditions are saved: [...] up is nullptr

Lambda is not a pointer. Lambda cannot be nullptr .

However, you are already creating your own local structure, why not just use it to protect the RAII region, and not defer it to unique_ptr ? This seems like a hack at best and requires more code to load. You could just do:

 template< typename lambda > auto make_scope_guard(lambda && _lambda) { struct lambda_caller { lambda _lambda; ~lambda_caller() { _lambda(); } }; return lambda_caller{std::forward<lambda>(_lambda)}; } 

If you need to support release , you can wrap _lambda inside boost::optional so that lambda_caller becomes:

 struct lambda_caller { boost::optional<lambda> _lambda; ~lambda_caller() { if (_lambda) { (*_lambda)(); _lambda = boost::none; } } void release() { _lambda = boost::none; } }; 
+4
source

All Articles