问题 为什么unique_ptr不能推断出删除器的类型?


假设我想使用带有unique_ptr的自定义删除器:

void custom_deleter(int* obj)
{
    delete obj; 
}

为什么我要写这个:

std::unique_ptr<int, void(*)(int*)> x(new int, custom_deleter);

而不是这个:

std::unique_ptr<int> x(new int, custom_deleter); //does not compile

不能推断出删除器的类型吗?


3480
2018-04-15 20:35


起源

有关: stackoverflow.com/questions/21355037/... - 0x499602D2
模板类不推断模板参数。只有模板功能才有。 - Cássio Renan
我想知道为什么 std::make_unique 没有可以指定删除器的重载。这样,您可以推断出删除器的类型。 - vsoftco
@vsoftco刚才我正在看文档并想知道同样的事情...... - Cássio Renan
@vsoftco怎么样?它必须采用参数包来构造 T。你如何区分哪一个? Args... 是个 Deleter? - Barry


答案:


对于 unique_ptr,删除器是类型的一部分:

template <
    class T,
    class Deleter = std::default_delete<T>
> class unique_ptr;

因此,在构建对象时,需要指定其类型。你写的那一行:

std::unique_ptr<int> x(new int, custom_deleter);

相当于:

std::unique_ptr<int, std::default_delete<int> > x(new int, custom_deleter);

你不能建造一个 std::default_delete<int> 从 custom_deleter

唯一的方法 推断 删除类型也是在该部分使用模板推导:

template <typename T, typename Deleter>
std::unique_ptr<T, Deleter> make_unique_ptr(T* ptr, Deleter deleter) {
    return std::unique_ptr<T, Deleter>(ptr, deleter);
}

6
2018-04-15 20:48



这正是我要做的 std::make_unique,没有看到为什么它没有这样实现的任何理由。 - vsoftco
@vsoftco [从上面复制]如何运作?它必须采用一个参数包来构造T.你如何区分哪一个Args ...是Deleter? - Barry
也许有一个 std::piecewise_construct / std::forward_as_tuple - vsoftco


它无法推断出删除器的类型,因为 unique_ptr 默认情况下没有专门用于删除器的状态:默认删除器是无状态的。

在你的情况下,删除器需要一个指针的状态,所以它不能“适合” std::unique_ptr的状态(这只是指向一个 T)。

这使得 unique_ptr 拥有指针的轻量级,几乎无成本的替代品。

Deductin可以完成,但它必须改变结果的类型 unique_ptr

相比下, shared_ptr 始终具有删除器的状态容量,两个不同的原子计数器和指向值的指针。它的重量更重,而且不是指针的免费替代品。


3
2018-04-16 02:51