引言
前面两篇介绍了std::unique_ptr
的自定义删除器以及如何优化删除器的使用。
本文将介绍std::unique_ptr
在使用过程中的一些“奇技淫巧”。
正文
删除器和std::move
std::move
是将对象的所有权转移给另一个对象,那如果通过std::move
来转移带自定义删除器的std::unique_ptr
对象时,对应的删除器会不会一起转移呢?
我们通过示例定义奇偶数的删除器来介绍:
void deleteEvenNumber(int* pi)
{std::cout << "Delete even number " << *pi << '\n';delete pi;
}void deleteOddNumber(int* pi)
{std::cout << "Delete odd number " << *pi << '\n';delete pi;
}using IntDeleter = void(*)(int*);
using IntUniquePtr = std::unique_ptr<int, IntDeleter>;int main() {{IntUniquePtr p1(new int(42), deleteEvenNumber);IntUniquePtr p2(new int(43), deleteOddNumber);p1 = move(p2);}return 0;
}
上面这个示例中,如果把p1 = move(p2);
代码注释掉,它的结果是:
Delete odd number 43
Delete even number 42
如果把代码还原回去后,结构是:
Delete even number 42
Delete odd number 43
从上面两个结果来看,std::move
不仅把对象的所有权转移了,同时也转移了删除器。
删除器和reset()
std::unique_ptr
的reset()
函数是用来重置智能指针的状态和其管理的对象。如果unique_ptr
定义了删除器,然后调用reset()
会出现什么效果呢?
还是用上面的示例,修改main()
函数:
int main() {{IntUniquePtr p1(new int(42), deleteEvenNumber);p1.reset(new int(43));}return 0;
}
结果是:
Delete even number 42
Delete even number 43
这个结果就说明reset()
不会对删除器产生任何影响。
但是这就产生一个问题,重置后的值并不是偶数,对应的删除器已经不符合需求了,但是reset()
又只能传一个参数,没有通过reset()
重置删除器,那要怎么解决呢?
方案一:
因为std::unique_ptr
提供了get_deleter()
函数来返回删除器的引用,所以我们可以通过该接口来手动修改删除器:
int main() {{IntUniquePtr p1(new int(42), deleteEvenNumber);p1.reset(new int(43));p1.get_deleter() = deleteOddNumber;}return 0;
}
运行结果:
Delete even number 42
Delete odd number 43
方案二:
第二种方案是用赋值来代替reset()
:
int main() {{IntUniquePtr p1(new int(42), deleteEvenNumber);p1 = IntUniquePtr(new int(43), deleteOddNumber);}return 0;
}
运行结果:
Delete even number 42
Delete odd number 43