Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vector with references to unique_ptr

I have a collection of unique_ptrs. 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_ptrs.

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_ptrs? I could also use shared_ptr, but the ownership is quite clear and as I mentioned the caller does not need write access.

like image 652
pschulz Avatar asked Feb 10 '18 11:02

pschulz


People also ask

Can I have a vector of unique_ptr?

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))); .

Should I use shared_ptr or unique_ptr?

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.

What is the difference between Auto_ptr and unique_ptr?

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.

What does unique_ptr mean in C++?

(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.


3 Answers

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;
}
like image 88
llllllllll Avatar answered Nov 15 '22 07:11

llllllllll


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;
}
like image 39
user9335240 Avatar answered Nov 15 '22 06:11

user9335240


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

like image 29
Gabriel Avatar answered Nov 15 '22 06:11

Gabriel