1

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.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
Charles
  • 545
  • 2
  • 7
  • 14
  • 1
    Are you sure you want `vector>>`? – Cheers and hth. - Alf Jan 08 '16 at 07:41
  • 1
    Unless the returned vector should own the objects, you should just return a vector of raw pointers, not `unique_ptr`s. From what I can see `things` should retain ownership of the objects. – Joel Cornett Jan 08 '16 at 07:41
  • @JoelCornett is that a good idea? Can't the consumer just ``delete'' the pointer at will? – Charles Jan 08 '16 at 07:42
  • @Charles if that is a genuine concern, than you should wrap the pointers in a custom class that prevents the user from deleting those objects. It's also possible you want shared ownership through `shared_ptr`. Unless you are transferring ownership of the object to the caller though, you do *not* want `unique_ptr`. – Joel Cornett Jan 08 '16 at 07:46
  • @JoelCornett I am not trying to share ownership - just give a read-only reference to a vector of objects owned by somebody else. Also, I am led to believe that passing a reference to a unique_ptr is the proper way to do this - http://stackoverflow.com/questions/8114276/how-do-i-pass-a-unique-ptr-argument-to-a-constructor-or-a-function – Charles Jan 08 '16 at 07:48
  • 2
    @Charles In the new world *raw pointers* should be treated as owned by someone else and no one should be deleting them (unless they happen to be writing a *smart pointer* or, perhaps, a container class). Calls to `new` and `delete` should, for the most part, be a thing of the past. – Galik Jan 08 '16 at 07:50
  • @Charles as far as I can tell, the question you cited doesn't pertain to your case. `unique_ptr` equals ownership, raw pointers are for "borrowing". If you want to provide read-only access, return a vector of `const Base*`. IOW, the `const` modifier is there to enforce read-only access. – Joel Cornett Jan 08 '16 at 07:55
  • Returning `unique_ptr`s to objects won't stop users from being able to delete them, btw. – Joel Cornett Jan 08 '16 at 08:00

1 Answers1

3

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

davidhigh
  • 14,652
  • 2
  • 44
  • 75