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.
This means that you can't make copies of a unique_ptr (because then two unique_ptr s would have ownership), so you can only move it. D.R. Since there can be only one, one should also be able to pass a temporary directly to the vector: vec. push_back(std::unique_ptr<int>(new int(1))); .
Use unique_ptr when you want a single pointer to an object that will be reclaimed when that single pointer is destroyed. Use shared_ptr when you want multiple pointers to the same resource.
unique_ptr is a new facility with a similar functionality, but with improved security. auto_ptr is a smart pointer that manages an object obtained via new expression and deletes that object when auto_ptr itself is destroyed.
(since C++11) std::unique_ptr is a smart pointer that owns and manages another object through a pointer and disposes of that object when the unique_ptr goes out of scope. The object is disposed of, using the associated deleter when either of the following happens: the managing unique_ptr object is destroyed.
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;
}
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;
}
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With