共享指针和具有自定义删除器的唯一指针之间的语法差异背后的任何原因

Joh*_* Li 2 c++ pointers smart-pointers

虽然 C++11 中的共享指针和唯一指针都允许用户定义删除器,但它们有显着的语法差异,如下面的小示例所示:

#include "pch.h"
#include <memory>
class factory
{
public:
    static factory * create() {
        return new factory();
    }
    static void destroy(factory*    fp) noexcept{
        delete fp;
    }
    factory(const factory &) = delete;
    factory& operator= (const factory &) = delete;
private:
    char * p_;
    factory() {
    p_ = new char[100];
    }
    ~factory() {
        delete[] p_;
    }
};

int main()
{
    typedef void(*fp)(factory*);

    auto del = [](factory * p) noexcept {
        factory::destroy(p);
    };

    std::shared_ptr<factory> fsptr1(factory::create(), del);
    std::shared_ptr<factory> fsptr2(factory::create(), del);
    //notice the syntax is different
    std::unique_ptr<factory, fp> ufsptr1(factory::create(), del);
    std::unique_ptr<factory, decltype(del)> ufsptr2(factory::create(), del);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这背后的原因是共享指针的模板类定义为

template< class T > class shared_ptr;
Run Code Online (Sandbox Code Playgroud)

唯一指针的模板类定义为

template<class T, class Deleter = std::default_delete<T>> class unique_ptr;
Run Code Online (Sandbox Code Playgroud)

我的问题是:在此设计决策背后是否有任何原因表明两者的语法彼此不同?我天真的想法是,如果共享指针的模板类是这样的

template< class T, class Deleter = std::default_delete<T>> class shared_ptr;
Run Code Online (Sandbox Code Playgroud)

它会更有意义。一方面,它与唯一指针的情况一致,另一方面,当默认删除器格式不正确并且用户无法提供自定义删除器时,它不会实例化。

Mat*_*her 5

默认std::unique_ptr仅存储一个元素,即指向它所保护的数据的指针。这是因为默认情况下,您希望使用尽可能少的内存。但是当您指定删除器时,您还需要存储它。所以你需要区分这两个版本。

见这里:https : //github.com/llvm-mirror/libcxx/blob/master/include/memory#L2397

存储是基于模板类型的特定类型。

但是对于std::shared_ptr,你没有这个约束,你已经有了一个计数器,你需要分配一个块来存储它。因此,您可以在 API 级别的分配逻辑内部而不是外部做出删除选择。

见这里:https : //github.com/llvm-mirror/libcxx/blob/master/include/memory#L3592

compressed_pair不是在智能指针本身,而是在分配的块。

  • @JohnZ.Li:EBO(空基优化)可能适用。 (2认同)
  • 是的,但是对于`shared_ptr`,您没有将删除器存储为唯一指针,而是分配了一个指针和计数器所在的块。所以如果你指定了一个删除器,你就可以分配更多来存储它。这可以在构造函数中使用删除器完成。对于 unique_ptr,您必须在两个实现之间静态切换。 (2认同)