c – unique_ptr的赋值操作符复制引用存储的删除器.是功能还是错
当您有一个unique_ptr与引用存储的自定义删除程序成像时:
struct CountingDeleter { void operator()(std::string *p) { ++cntr_; delete p; } unsigned long cntr_ = 0; }; int main() { CountingDeleter d1{},d2{}; { std::unique_ptr<std::string,CountingDeleter&> p1(new std::string{"first"},d1),p2(new std::string{"second"},d2); p1 = std::move(p2); // does d1 = d2 under cover } std::cout << "d1 " << d1.cntr_ << "n"; // output: d1 1 std::cout << "d2 " << d2.cntr_ << "n"; // output: d2 0 } 对我来说,令人吃惊的是,上述代码中的赋值对d2进行了复制.我仔细检查一下,发现这个行为是在[unique.ptr.single.asgn]标准中描述的:
为了获得我预期的行为(一个浅拷贝的删除引用),我不得不将删除引用包装到std :: reference_wrapper中: std::unique_ptr<std::string,std::reference_wrapper<CountingDeleter>> p1(new std::string{"first"},d2); p1 = std::move(p2); // p1 now stores reference to d2 => no side effects! 对于我来说,目前在独特的ptr中处理一个删除引用是反直觉甚至容易出错的: >当您使用引用而不是按值存储删除器时,这主要是因为您希望共享删除程序具有一些重要的独特状态.所以你不要指望共享删除器被覆盖,并且在一个唯一的ptr赋值之后它的状态丢失. IMO最好禁止参考类型的删除者,只接受可移动的值类型. 所以我的问题是如下(它看起来像是两个问题,对不起): >为什么标准的unique_ptr行为是这样的? 解决方法
这是一个功能.
如果你有状态的删除者,可能状态是重要的,并且与将被用于删除的指针相关联.这意味着当指针的所有权转移时应该转移删除状态. 但是,如果通过引用存储删除器,则意味着您关心删除者的身份,而不仅仅是其值(即它的状态),并且更新unique_ptr不应将引用重新绑定到另一个对象. 所以如果你不想要这个,你为什么甚至通过参考存储一个删除器? 参考文献的浅层副本甚至意味着什么? C中没有这样的东西.如果您不希望引用语义,请不要使用引用. 如果你真的想这样做,那么解决方案很简单:为你的删除器定义分配,不要改变计数器: CountingDeleter& operator=(const CountingDeleter&) noexcept { return *this; } 或者,因为你真正关心的是计数器,而不是去除器,将计数器保留在除去器外,不要使用参考去除器: struct CountingDeleter { void operator()(std::string *p) { ++*cntr_; delete p; } unsigned long* cntr_; }; unsigned long c1 = 0,c2 = 0; CountingDeleter d1{&c1},d2{&c2}; { std::unique_ptr<std::string,CountingDeleter> p1(new std::string{"first"},d2); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |