unique_ptr和默认的可构造指针

Ori*_*ent 5 c++ lambda unique-ptr c++11 c++14

最近,我试图彻底改造范围后卫通过std::unique_ptr(:缺失者有成员类型定义pointer-是的特殊处理情况下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;
}
Run Code Online (Sandbox Code Playgroud)

这种方法适用于void f() { std::cout << 4 << std::endl; }传递给自由函数的简单指针make_scope_guard,但不适用于传递给它的任何lambda make_scope_guard.

这是由于大量的... = pointer()进入std::unique_ptr定义(函数默认参数,默认数据承包商,客人等等),但我不能找到缺省构造的要求对pointer这个文章.

它是强制性的,pointer应该符合std::is_default_constructible要求吗?

这对测试libc++和反对libstdc++使用不是太旧clang++ -std=gnu++1z.

似乎,lambdas应该有语言扩展:如果auto l = [/* possible capture list */] (Args...) { /* code */; };那么using L = decltype(l);等同struct L { constexpr void operator () (Args...) const noexcept { ; } };于某些Args...,不是吗?

额外:

提供了实例D{}以下的可缺省make_scope_guard(D{})需要注释的代码中的上下文中未注释if (p) { ...,其中p的类型为D:

struct D { void operator () () const noexcept { std::cout << __PRETTY_FUNCTION__ << std::endl; } /* constexpr operator bool () const { return true; } */ };
Run Code Online (Sandbox Code Playgroud)

Bar*_*rry 4

Aunique_ptr仍然是一个指针。你不能把 lambda 硬塞进去。来自[unique.ptr]:

唯一指针是一个拥有另一个对象并通过指针管理另一个对象的对象。更准确地说,唯一指针是一个对象 u,它存储指向第二个对象 p 的指针,并且当 u 本身被销毁时将处理 p

[...]

此外,u可以根据请求将所有权转移给另一个唯一指针u2。完成此类传输后,以下后置条件成立: [...] up等于nullptr

lambda 不是指针。lambda 不能等于nullptr

也就是说,您已经在创建自己的本地结构,为什么不直接使用来保护自身的 RAII 范围而不是遵循unique_ptr?这看起来充其量只是一种黑客攻击,并且需要更多代码来启动。你可以这样做:

template< typename lambda >
auto
make_scope_guard(lambda && _lambda)
{
    struct lambda_caller
    {
        lambda _lambda;

        ~lambda_caller()
        {
            _lambda();
        }

    };

    return lambda_caller{std::forward<lambda>(_lambda)};
}
Run Code Online (Sandbox Code Playgroud)

如果需要支持release,可以将 包裹_lambda起来,boost::optional这样就lambda_caller变成:

struct lambda_caller
{
    boost::optional<lambda> _lambda;

    ~lambda_caller()
    {
        if (_lambda) {
            (*_lambda)();
            _lambda = boost::none;
        }
    }

    void release() {
        _lambda = boost::none;
    }
};
Run Code Online (Sandbox Code Playgroud)