在foreach循环中将指针隐式转换为std :: unique_ptr

时间:2019-11-20 23:12:58

标签: c++ memory-management unique-ptr

我有一个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

是否可以通过这种方式将容器的每个元素转换为智能指针,还是需要显式删除原始指针?

3 个答案:

答案 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