Charles
Charles

Reputation: 575

C++11 converting a unique_ptr to a base class

I have a function which takes some vector of objects and filters it and needs to return the filtered vector of objects converted to a base class.

class Base {
    // stuff
}

class Derived : public Base {
    // more stuff
}

// elsewhere...
vector<reference_wrapper<const unique_ptr<Base>>> do_something(const vector<unique_ptr<Derived>> &things) {
    vector<reference_wrapper<const unique_ptr<Base>>> a;

    for (const unique_ptr<Derived> &derived : things) {
        if (check(derived)) {
            a.push_back(derived);  // this obviously doens't work -
                                   // what should I put here?!

            // this does not work:
            // a.push_back(std::ref(derived.get()))
            // because derived.get() is an rvalue
        }
    }

    return a;
}

The returned vector doesn't own any of the original objects - they should just be readers. The original objects will outlive the lifespan of the returned vector.

Upvotes: 1

Views: 648

Answers (1)

davidhigh
davidhigh

Reputation: 15488

I haven't read the comments, so maybe it's answered there already. Usually, however, when the vector doesn't own any of its pointed-to members, one does not use a reference to unique_ptr -- as this expresses, the vector should be able to do certain things with the unique_ptr only the owner can.

The common approach for a complete observer is rather to use a raw pointer (at least until observer_ptr is in the standard library). The constraint is that you shall never call delete or any other memory-related operation on those pointers (this is what observer_ptr disallows by design).

So you write:

auto do_something(vector<unique_ptr<Derived>> const&things)
{
    vector<Base *> a;

    for (auto& derived : things) {
        if (check(derived))
        {
            a.push_back(derived.get());
        }

    return a;
}

Short comparison to your case where you chose a reference to a const unique_ptr: The callable const functions in the unique_ptr interface are given by get(),get_deleter() and operator bool(). Of those three, with the vector<Base *> approach you loose the possibility to call get_deleter(). However, as only a reader, one almost surely does not need the deleter.

Scott Meyer (and his references) gave a slightly related discussion which could be of interest here: http://scottmeyers.blogspot.de/2014/07/should-move-only-types-ever-be-passed.html

Upvotes: 3

Related Questions