Unique_ptr和默认的可构造指针
unique_ptr and default constructible pointer
最近我尝试通过std::unique_ptr
重新定义作用域保护 (注意: Deleter具有成员类型pedef 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;
}
对于传递给make_scope_guard
的自由函数void f() { std::cout << 4 << std::endl; }
的简单指针,这种方法可以很好地工作,但对于传递给make_scope_guard
的lambda则不行。
这是由于std::unique_ptr
定义中有大量的... = pointer()
(函数默认参数,默认数据成员等),但我无法在本文中找到pointer
的DefaultConstructible要求。
是强制性的,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...
,不是吗?
附加:
为make_scope_guard(D{})
提供以下DefaultConstructible类的实例D{}
,要求在if (p) { ...
上下文中取消注释掉的代码,其中p
的类型为D
:
struct D { void operator () () const noexcept { std::cout << __PRETTY_FUNCTION__ << std::endl; } /* constexpr operator bool () const { return true; } */ };
unique_ptr
仍然是一个指针。你不能把一个塞进去。从[unique.ptr]:
唯一指针是拥有另一个对象并通过指针管理该对象的对象。更准确地说,唯一指针是一个对象u,它存储指向第二个对象p的指针,并将其释放P
[…]此外,u可以根据请求将所有权转移给另一个惟一的指针u2。完成后这样的转移,下列后置条件成立:[…]] u。p等于
nullptr
lambda不是指针。一个lambda不能等于nullptr
。
unique_ptr
?这看起来充其量只是一个hack,并且需要更多的代码来启动。你可以这样写:
template< typename lambda >
auto
make_scope_guard(lambda && _lambda)
{
struct lambda_caller
{
lambda _lambda;
~lambda_caller()
{
_lambda();
}
};
return lambda_caller{std::forward<lambda>(_lambda)};
}
如果你需要支持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;
}
};
- C++默认情况下,指针类型数组的元素是否保证初始化为 nullptr?
- 为什么指针对象没有调用默认构造函数
- 默认参数和函数指针作为函数参数C++
- 为什么在使用指针时不采用类成员的默认值,而不是直接实例化对象时?
- 当指针在 cpp 17 中失去引用时,是否会调用非默认析构函数?
- char指针或char变量的默认值是多少
- 在一行中将默认类型值上的指针作为参数传递
- 如何使用带有非默认构造函数的指针来提升序列化
- 指针参数的默认值
- 不能将指针用作默认模板参数
- 模板默认参数作为指向自身的指针
- 指针的默认值
- 原始指针的默认删除器(unique_ptr)
- 常量指针到成员是否默认指向 int?
- 从指针访问值或获取其默认值(如果为 null)的最干净方法
- C 如何删除指针的默认对象成员
- 唯一指针作为默认参数
- 在Qt中,指针默认不与NULL关联
- 调试断言失败(无效空指针)默认字符串参数
- 从动态分配的解引用指针默认初始化非const引用函数参数是否会造成内存泄漏?