考虑一些功能:
template<typename F>
void foo(F f) {
std::unique_ptr<int> p = f();
// do some stuff with p
}
因为unique_ptr
为default_delete
命令默认模板参数D
,所以传递给foo
的任何函数对象返回带有非unique_ptr
的{{1}}默认删除器无法编译。例如,
int x = 3;
foo([&x](){
// use empty deleter
return std::unique_ptr<int>(&x, [](int*){});
});
然而,我可以看到这可能是有用的,我没有看到它为什么不可能的直接原因。是否有解决这个问题的常用方法?
修改
简单的解决方法是定义foo
而不是使用以下内容:
std::unique_ptr<int, std::function<void(int*)>> p = f();
但我想知道为什么这不能被合并到unique_ptr
的界面中?是否有类接口无法提供此通用属性的原因?是否存在将这种事物“包装”成新定义的方法?
例如,
template<typename T>
using Generic_unique_ptr =
std::unique_ptr<
T,
std::function< void(typename std::unique_ptr<T>::element_type*) >
>;
但这似乎很危险,因为它暴露了做下面这样的事情的潜力,
Generic_unique_ptr<int> p(new int());
会使删除者未初始化并显示未定义的行为。或许可以通过某种方式将 std::default_delete<T>
的实例作为默认删除工具?
答案 0 :(得分:4)
如果你想要的只是在函数中使用指针,你可以
使用auto
关键字;编译器将推导出unique_ptr
的类型
已被使用,从而自动做正确的事情:
template <typename F>
void foo(F f)
{
auto p = f();
p->bar();
}
现在,根据您的评论,我们知道这不是您想要的全部,而是您
希望能够将unique_ptr
存储在您的班级中以便使用
它以后。这会产生一系列完全不同的问题:
unique_ptr<T, D1>
和unique_ptr<T, D2>
是不同的类型。因此,我们需要知道您的仿函数unique_ptr<T, D>
F
F
的返回类型,我们的班级仍然只能存储unique_ptr<T, D1>
而不是unique_ptr<T, D2>
。最简单的方法(我能想到的,可能会更好 方法)是类型擦除。
我们自己创建一个基类,公开由...管理的指针
unique_ptr
:
template <typename T>
struct wrapper
{
virtual ~wrapper() {}
virtual T const * get() const = 0;
virtual T * get() = 0;
};
从该类继承我们的实际存储类,它会推断出类型
unique_ptr
:
template <typename T, typename F>
struct storage
: wrapper<T>
{
storage(F f) { p_ = f(); }
T const * get() const { return p_.get(); }
T * get() { return p_.get(); }
private:
typename std::result_of<F()>::type p_;
};
在您真正关心的课程中,您现在可以存储指向我们的指针
基类和使用多态来访问底层对象,在此
案例unique_ptr
。假设我们将上面的类移到了
namespace detail
将其隐藏在用户之外:
template <typename T>
class some_class
{
public:
template <typename F>
void store(F f)
{
storage_.reset(new detail::storage<T, F>(f));
}
T const * get() const { return storage_->get(); }
T * get() { return storage_->get(); }
private:
std::unique_ptr<detail::wrapper<T>> storage_;
};
您可以找到一个完整的示例here。
答案 1 :(得分:2)
但我想知道为什么这不能合并到unique_ptr的接口中?
因为这样做会迫使所有std::function
的开销进入所有人。 unique_ptr
旨在用于指针的单个所有权的任何情况。你支付你使用的费用;并非所有使用自定义删除程序的人都需要将删除程序设为通用。这样,他们就不用付钱了。
此外,当前的方法允许它处理非指针资源,因为删除器可以准确指定unique_ptr
中存储的类型。
如果要提供此通用删除器构造,可以创建一个(私有地)从unique_ptr
继承并复制其接口的类,减去不带删除器实例的构造函数。这样,用户就被迫传递了删除函数。