问题
I have a collection of unique_ptr
s. Here i want to take some of them and return them to the caller. The caller only needs to read the content, so i wanted to use constant references. But I'm not sure how to do this with unique_ptr
s.
Here is some code I used to do this with raw pointers:
class entry
{
};
vector<entry*> master;
const vector<entry*> get_entries()
{
vector<entry*> entries;
// peusocode, master contains all entries.
// only some entries are copied, filtered by some predicate
copy_if(master.begin(), master.end(), back_inserter(entries), ...);
}
How do I do this with unique_ptr
s? I could also use shared_ptr
, but the ownership is quite clear and as I mentioned the caller does not need write access.
回答1:
Unique pointer is a "value type" containing a pointer.
So you could treat it as if it is a value type.
But it is uncopyable. So, the solution maybe use const references.
This also can't be applied to "vector" types. So, the solution is to use the reference_wrapper
//type alias for readability
using uEntry = std::unique_ptr<Entry>;
std::vector<uEntry> entries;
std::vector<std::reference_wrapper<const uEntry>> getEntries() {
std::vector<std::reference_wrapper<const uEntry>> priventries;
std::for_each(entries.begin(), entries.end(), [&](const uEntry &e) {
if (e->a > 5) {
priventries.push_back(std::cref<uEntry>(e));
}
});
return priventries;
}
int main(int argc, const char * argv[]) {
entries.push_back(uEntry(new Entry(5)));
entries.push_back(uEntry(new Entry(7)));
std::cout << getEntries().size();
return 0;
}
回答2:
The caller only needs to read the content
If the caller won't participate in the ownership of the pointer, then just use raw pointer. In fact, raw pointer can be considered as a pointer without ownership.
std::vector<std::unique_ptr<entry>> master;
std::vector<const entry*>
get_entries()
{
std::vector<const entry*> entries;
for ( auto const &ptr : master ) {
/* if something satisfied */
entries.push_back(ptr.get());
}
return entries;
}
回答3:
If you have a vector of unique_ptr and you want to return some of them to the caller you can iterate on the vector and collect raw pointers in another vector and return it. One efficient when you work with smart pointers convention is to use raw pointers for reading, and leave unique_ptr and shared_ptr for memory management
vector<entry*> collect(const vector<unique_ptr<entry>>& data){
vector<entry*> result;
for (auto const & it: data){
if (ShouldBeCollected()){
result.push_back(it.get())
}
}
return result;
}
So keep cool and don't delete raw pointers
回答4:
The type of the elements contained by a std::vector
must be assignable. References can't be assigned-to (only initialized).
If using raw pointers is not an issue, becasue the caller doesn't take part in the ownership, you could use raw pointers to const
entry
instead:
vector<const entry *> get_entries();
If you want to use smart pointers, you have to consider that assigning a std::unique_ptr
to a std::shared_ptr
will transfer the ownership of the pointer. That is, the moved-from std::unique_ptr
object becomes empty: it doesn't own a pointer anymore.
Therefore, you may want to consider a complete transition from std::unique_ptr
to std::shared_ptr
for your collection.
回答5:
By circumstances of OP the solution must look like bellow. I leave to OP how he would apply std::copy_if
.
#include <memory>
#include <vector>
#include <algorithm>
class entry {
};
std::vector<std::unique_ptr<entry>> master;
std::vector<const entry*> get_entries()
{
std::vector<const entry*> entries;
// only some entries are copied, filtered by some predicate
std::transform(master.begin(), master.end(), std::back_inserter(entries),
[](const auto& up){return up.get();});
return entries;
}
来源:https://stackoverflow.com/questions/48720204/vector-with-references-to-unique-ptr