我有一个api调用,该调用填充了供调用者使用的原始指针数组。此函数堆分配每个原始指针,但不分配数组。
无论该API函数有多糟糕,我都无法对其进行更改。
调用api函数代码看起来像这样:
size_t response_count = api.getResponseCount();
std::vector<Response*> responses(response_count);
api.getResponses(responses.data());
for(auto response : responses) {
// Do some processing with response
delete response;
}
我想将每个响应包装在unique_ptr中,以便在循环迭代结束时仍可以清除它,而不必显式调用delete。理想情况下,看起来应该像这样:
for(std::unique_ptr<Response> response : responses) {
// Do some processing with response
// No need to delete response, it will be cleaned up as it goes out of scope
}
这不会编译,因为编译器无法将指针转换为unique_ptr:
error: conversion from ‘Response*’ to non-scalar type ‘std::unique_ptr<Response>’ requested
是否可以通过这种方式将容器的每个元素转换为智能指针,还是需要显式删除原始指针?
答案 0 :(得分:3)
我会考虑使用Boost ptr_vector
。而不是将每个指针包装在unique_ptr
中。
假设已分配数据,那么您实际上可以使用delete
将其删除,代码如下所示:
size_t response_count = api.getResponseCount();
// Unfortunately, we have to define, then resize. It has a ctor that takes a size,
// but it treats that as an amount to reserve rather than an actual size.
boost::ptr_vector<Response> responses;
responses.resize(response_count);
api.getResponses(responses.c_array());
for(auto response : responses) {
// Do some processing with response
}
...并且responses
超出范围时,它将删除其包含的指针所指向的所有对象。如有必要,您可以指定一个Allocator
类,该类定义如何分配和删除对象。
参考
https://www.boost.org/doc/libs/1_71_0/libs/ptr_container/doc/ptr_container.html
答案 1 :(得分:1)
尽管不是很好的做法,但是您可以使用非显式构造函数从unique_ptr
派生。
template<typename P>
struct MakeUnique : std::unique_ptr<P> {
MakeUnique(P* p) : std::unique_ptr<P>(p) {}
};
然后可以这样使用:
for ( MakeUnique<Response> resp : responses ) {
...
}
可能是最接近单线的东西。参见工作版本here。
答案 2 :(得分:0)
您可以为vector<response*>
创建一个分发唯一指针的包装器
struct wrapper{
struct iterator {
iterator( std::vector<response*>::iterator it ) : it_(it){}
friend bool operator!=( iterator const& lhs, iterator const &rhs ){ return lhs.it_ != rhs.it_; }
void operator++(){ ++it_;}
std::unique_ptr<response> operator*(){ return std::unique_ptr<response>(*it_); }
private:
std::vector<response*>::iterator it_;
};
wrapper( std::vector<response*>& rs ) : rs_{rs} {}
iterator begin() const { return iterator{rs_.begin()}; }
iterator end() const { return iterator{rs_.end()}; }
private:
std::vector<response*>& rs_;
};
然后您可以遍历以下响应:
for( auto resp : wrapper( responses ) ){...
}
请参阅工作版本here。