C++ 使用std::使用自定义删除器使_唯一

C++ 使用std::使用自定义删除器使_唯一,c++,c++11,c++14,C++,C++11,C++14,在对自定义删除程序使用std::unique_ptr时,我希望使用std::make_unique而不是原始的新删除程序。我正在使用VC++2013。在我看来,如果您使用的是自定义删除程序,则无法使用std::unique\u ptr。我是错过了什么还是真的错过了 其他信息: 我正在使用std::unique_ptr为打开的COM端口保存Windows句柄 我可以为此编写一个定制的RAII类,这不会非常困难,但我看到了使用std::unique\u ptr的困难/困难/糟糕,make\u un

在对自定义删除程序使用
std::unique_ptr
时,我希望使用
std::make_unique
而不是原始的新删除程序。我正在使用VC++2013。在我看来,如果您使用的是自定义删除程序,则无法使用
std::unique\u ptr
。我是错过了什么还是真的错过了


其他信息:

我正在使用
std::unique_ptr
为打开的COM端口保存Windows句柄


我可以为此编写一个定制的RAII类,这不会非常困难,但我看到了使用
std::unique\u ptr
的困难/困难/糟糕,
make\u unique
的全部目的是封装“使用
new
从给定的构造函数参数创建
T
,并使用
delete
销毁它”

如果您想要一个定制的删除器,您还必须指定如何创建该对象,那么使用emplacing maker函数将不会有更多的好处


我为某些独特的资源句柄编写了一些定制函数的示例。

据我所知,C++11标准中没有
make_unique
函数。请参阅

因此,我假设
make_unique
是微软的一个实现,至少没有包含在标准中


但是,您可以将自定义删除程序与
unique\u ptr
一起使用。当使用
unique\u ptr
时,您必须将删除程序的类型指定为第二个模板参数,然后将适当的对象传递给构造函数。

下面是一种使用自定义调用自定义自由函数的删除程序。它有一个类似于
std::make_unique


是的,这似乎是
make_unique
中的一个缺陷。用例是什么?如果您使用
std::make_unique
,它使用
new
进行分配,因此默认的删除器(使用
delete
)是正确匹配的删除器。理论上可以指定“创建者”“还有一个删除程序,然后您就可以享受异常安全的好处了。@LucDanton:是和否。
allocate\u shared
只使用用户定义的分配器,而不是删除程序。这是一个不太强大的概念。例如,不能将
std::FILE*
包装在该文件中。换句话说,
allocate\u shared
并不公开
std::shared\u ptr
的全部功能,它只允许您自定义内存分配器。啊!在我看来,他们定义“使你独一无二”的方式几乎毫无用处。仅使用唯一的\u ptr构造函数,它真正为我们带来了什么好处?我真正想要的是一个make_unique变量,它接受deleter作为参数,这样就可以推断出它的类型。这将使我能够为deleter创建具有无法表达类型的唯一\u ptr。例如:
autop=std::make_unique(x,y,z,[](Foo*obj){fancyfreeffunction(obj);})这是一个很好的观点。我想这会让我们陷入整个
allocate\u unique
辩论。在我上面的即兴示例中,唯一的方法是新操作员。@Petrruderman:分配和删除在某种程度上是分开的。想想
fopen
/
fclose
。如果您只需要一个普通的唯一指针以及从分配器获得的内存,那么可以使用
分配器\u deleter
,但这只能解决问题域的一部分。C++14将添加std::make_unique。不幸的是,无法在std::make_unique中指定delete,因此它只能返回带有默认delete的唯一指针。
#include <iostream>
#include <functional>
#include <memory>

// Some C style code that has some custom free function ptr...
extern "C" {

struct ABC { };

enum free_type_e {
    FREE_ALL,
    FREE_SOME
};

typedef void (free_f)(enum free_type_e free_type, void *ptr);
struct some_c_ops { free_f* free_op; };

void MY_free(enum free_type_e free_type, void *ptr)
{
    printf("%s:%d ptr=%ld\n", __func__, __LINE__, (long)ptr);
    (void)free_type;
    free(ptr);
}

}; // extern "C"

template<typename T>
using c_unique_ptr = std::unique_ptr<T,std::function<void(T*)>>;

template <typename T>
c_unique_ptr<T> make_c_unique(some_c_ops* op, free_type_e free_type)
{
    return c_unique_ptr<T>(static_cast<T*>(calloc(1, sizeof(T))),
                           std::bind(op->free_op, free_type, std::placeholders::_1));
}

void foo(c_unique_ptr<ABC> ptr)
{
    std::cout << __func__ << ":" << __LINE__
        << " ptr=" << reinterpret_cast<size_t>(ptr.get()) <<     std::endl;
}

int main()
{
    some_c_ops ops = { MY_free };
    c_unique_ptr<ABC> ptr = make_c_unique<ABC>(&ops, FREE_ALL);
    std::cout << __func__ << ":" << __LINE__
        << " ptr=" << reinterpret_cast<size_t>(ptr.get()) << std::endl;

    foo(std::move(ptr));

    std::cout << __func__ << ":" << __LINE__
        << " ptr=" << reinterpret_cast<size_t>(ptr.get()) << std::endl;
}
main:48 ptr=50511440
foo:40 ptr=50511440
MY_free:20 ptr=50511440
main:53 ptr=0