new一个指针再被智能指针接管和直接调用make_unique有什么区别? (接上篇的未完待续)
上篇代码有错误在本篇幅更正#include iostream #include memory #include vector #include utility #include cstddef #include type_traits //std::enable_if_t!std::is_arrayT::value, int 0 template typename T struct DefaultDelete { //必须加const为了兼容后面const类型的智能指针 void operator()(T* ptr) const { if (ptr) { std::cout use T deleter_() std::endl; delete ptr; } } }; //利用模板的特化去匹配数组类型 template typename T struct DefaultDeleteT[] { void operator()(T *ptr) const { if (ptr) { std::cout use T[] deleter_() std::endl; delete[] ptr; } } }; template typename T, typename Delete DefaultDeleteT class MyUniquePtr { private: T *ptr_; Delete deleter_; public: //允许外部自定义删除类在构造函数这里传入, 所以也需要移动构造删除器 inline explicit MyUniquePtr(T *data, Delete del Delete()) : ptr_(data), deleter_(std::move(del)) { std::cout MyUniquePtrT std::endl; } inline ~MyUniquePtr() noexcept { if (ptr_) { std::cout ~MyUniquePtrT std::endl; deleter_(ptr_); ptr_ nullptr; } } MyUniquePtr(const MyUniquePtr ptr) delete; MyUniquePtr operator(const MyUniquePtr ptr) delete; inline MyUniquePtr(MyUniquePtr other) : ptr_(other.ptr_), deleter_(std::move(other.deleter_)) { other.ptr_ nullptr; } inline MyUniquePtr operator (MyUniquePtr other) { if (this other) { return *this; } reset(other.ptr_); deleter_ std::move(other.deleter_); other.ptr_ nullptr; return *this; } inline T operator* () const noexcept { return *ptr_; } inline T* operator- () const noexcept { return ptr_; } inline explicit operator bool() const noexcept { return (ptr_ ! nullptr); } inline void reset(T *data) { T *tmp ptr_; ptr_ data; if (tmp) { deleter_(tmp); } } T *get_ptr() const noexcept { return ptr_; } }; template typename T, typename Delete class MyUniquePtrT[], Delete { private: T *ptr_; Delete deleter_; public: inline explicit MyUniquePtr(T *data, Delete del Delete()) : ptr_(data), deleter_(std::move(del)) { std::cout MyUniquePtrT[] std::endl; } inline ~MyUniquePtr() noexcept { if (ptr_) { std::cout ~MyUniquePtrT[] std::endl; deleter_(ptr_); ptr_ nullptr; } } MyUniquePtr(const MyUniquePtr ptr) delete; MyUniquePtr operator(const MyUniquePtr ptr) delete; inline MyUniquePtr(MyUniquePtr other) : ptr_(other.ptr_), deleter_(std::move(other.deleter_)) { other.ptr_ nullptr; } inline MyUniquePtr operator (MyUniquePtr other) { if (this other) { return *this; } reset(other.ptr_); deleter_ std::move(other.deleter_); other.ptr_ nullptr; return *this; } inline explicit operator bool() const noexcept { return (ptr_ ! nullptr); } inline void reset(T *data) { T *tmp ptr_; ptr_ data; if (tmp) { deleter_(tmp); } } /* 不用int原因是禁止负索引 */ inline T operator[] (size_t index) const { return ptr_[index]; } T *get_ptr() const noexcept { return ptr_; } }; templatetypename T, typename ... Args, std::enable_if_t!std::is_arrayT::value, int 0 MyUniquePtrT myMakeUnique(Args ... args) { return MyUniquePtrT(new T(std::forwardArgs(args)...)); } templatetypename T, std::enable_if_tstd::is_arrayT::value std::extentT::value 0, int 0 MyUniquePtrT myMakeUnique(size_t size) { return MyUniquePtrT(new std::remove_extent_tT[size]()); } int main() { MyUniquePtrint[] p myMakeUniqueint[](6); MyUniquePtrint a myMakeUniqueint(); }构造函数里面 Delete del Delete() 为什么这样写可以这样写吗 Delete del deleter_因为template typename T, typename Delete DefaultDeleteT 这里typename Delete默认就是DefaultDeleteT 这个类所以说Delete()编译器能找到与之匹配的实体类DefaultDeleteDelete()相当于DefaultDeleteT(), 直接写DefaultDeleteT()也行只不过声明模板时候已经写了默认等于DefaultDeleteT 为了简写直接Delete()就好。Delete del deleter_正确吗本意是用类内默认构造器对象但是问题在于这是在构造函数内部类中变量都没有分配内存完成就直接用整个MyUniquePtr类没有构建出来时候, 也就是没有定义实体对象时候, 也就是MyUniquePtr p; 没有定义对象没有实体内存分配出来时, deleter_没有内存里面的成员变量直接用会导致未定义行为调用Delete类中拷贝构造时候, 用到deleter_入参传入但是deleter连内存都没有, 直接出现了问题所以最好用Delete() 现用现构造技巧(单例模式) 出临时对象, 去拷贝构造给deleterC中make_unique调用函数有啥好处注意C17之前函数参数里面的执行顺序是不确定的, 可能存在交替执行的流程之前的new操作是暴露在外的用effective c中的例子函数声明 int priority(); void processWidget(std::shared_ptrWidget pw, int priority_); 函数调用 processWidget(std::shared_ptrWidget(new Widget), priority()); C17之前参数里的执行顺序是不确定的, 上述代码会有什么问题 执行顺序 1. new Widget堆中构造内存 2. std::shared_ptrWidget智能指针接管 3. priority() 如果真的按照上述流程执行那就没问题, 也即C17现在是没问题的, C17能保证先完成一个参数处理完事再处理下一个参数 但是C17之前 可能会这样执行顺序 1. new Widget堆中构造内存 2. priority() 3. std::shared_ptrWidget智能指针接管 如果priority()函数抛异常 那么堆内存没有被智能指针接管导致内存泄漏这就是问题make_unique优势在哪里能解决上面讨论的这个问题?make_unique利用工厂模式, 用到时候去构造临时对象返回一个对象他把分配堆内存和智能指针接管操作凑在一个函数体执行这样能把他俩操作绑定成一个函数操作processWidget(std::make_uniqueWidget(), priority()); 这样流程会不会有问题执行顺序1. std::make_uniqueWidget()代码执行由于将分配内存和智能指针接管变成一个操作那么不是他先就是priority()先假如1. std::make_uniqueWidget()2. priority()此时priority()抛出异常那么堆内存已经被智能指针接管了不会泄漏然后由于泡异常C能保证函数执行过程中抛异常函数展开栈内存会得到释放所以智能指针对象被析构即堆内存被释放掉所以强异常安全。换个执行顺序同理总之能用make_unique构造智能指针就用他吧
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2638900.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!