我有一个std::vector<std::unique_ptr<Kind>>
,我想在迭代它时清理它,而不显式调用其成员的析构函数(.reset()
(。
Kind
是一个沉重的结构,它的大小在迭代过程中会增加。下一个对象不需要知道以前的对象,所以我想在不需要iterand的时候清理它。
我知道vector最终会清理干净,但到那时,许多Kind
和它们动态分配的内存加起来了。我正试图将峰值记忆减少到一个元素。
我想避免reset
,因为其他开发人员可能不知道动态分配,忘记了在循环结束时调用reset和消耗内存。
我无法创建副本,
for(std::unique_ptr<Kind> t : store)
我不能像那样移动它
for(std::unique_ptr<Kind> &&t : store)
那我该怎么做呢?
#include <iostream>
#include <vector>
struct Kind{
char a;
char *array;
Kind(const char c): a(c)
{
}
~Kind(){
free(array); // internal custom deallocator.
}
};
int main() {
std::vector<std::unique_ptr<Kind>> store;
store.push_back(std::make_unique<Kind>('y'));
store.push_back(std::make_unique<Kind>('z'));
for(std::unique_ptr<Kind> &t : store){
// increase size of Kind.array.
std::cout << t->a;
// Use the Kind.array
// clean up t automatically.
}
return 0;
}
将元素移出向量的示例。
int main() {
std::vector<std::unique_ptr<Kind>> store;
store.push_back(std::make_unique<Kind>('y'));
for(std::unique_ptr<Kind> &t : store){
auto tmp = std::move(t); // leaving a valid but empty entry in store
std::cout << tmp->a;
// clean up t automatically.
// tmp runs out of scope and cleans up
}
return 0;
}
实际上,与重置没有太大区别,但可能与您在实际程序中实际做的事情有关。
如何在使用基于范围的for循环遍历std::unique_ptr的std::vector时获得对象的所有权?
循环引用元素,std::move
将唯一指针指向另一个元素。示例:
for(std::unique_ptr<Kind> &t : store){
std::unique_ptr<Kind> owner = std::move(t);
// do something with newly owned pointer
我想清理
没有必要在周围保留较旧的结构
您可以通过重置指针来解除分配对象:
for(std::unique_ptr<Kind> &t : store) {
// do something
t.reset();
也就是说,这通常是不必要的。当矢量超出范围时,它们将被自动销毁。
我正试图在这里保存一些内存
如果在迭代时分配动态对象,这可能会很有用。否则,它不会影响峰值内存使用。
如果你想确保在每次迭代后立即删除实例,并且不能等到整个循环完成,你可以编写一个包装器来处理这个问题,同时表达你的意图:
template <typename T>
struct Stealing {
std::unique_ptr<T> ptr;
Stealing(std::unique_ptr<T>& ptr) : ptr(std::move(ptr)) {
}
auto operator*() {
return ptr.operator*();
}
auto operator->() {
return ptr.operator->();
}
}
您可以在循环中使用它来替换unique_ptr,如下所示:
for (Stealing<Kind> t: store) {
// do what you like with t as if it was a std::unique_ptr
// when t goes out of scope, so does its member -> Kind gets destroyed
}