0

I've got a vector std::vector<MyClass> myclass_vec(10) with 10 initialized objects of MyClass. Now I would like to loop over this vector and store a reference to every MyClass object in another vector std::vector<MyClass> myclass_vec_refs. The reason why I would like to store references is so because I don't have to copy the objects and obviously, refer to the same object as in myclass_vec.

For some reason, this doesn't work out as aspected. Do I have to declare std::vector<&MyClass> myclass_vec_refs like so?

As I was looking through other questions asked here I read about std::unique_ptr. If I change std::vector<std::unique_ptr<MyClass>> myclass_vec(10) then I wouldn't able to have a reference or pointer in myclass_vec_refs since they are declared unique. Correct me please if I'm mistaken.

Another approach was using std::shared_ptr. Since it holds a reference counter I would be able to have myclass_vec_refs point to objects in myclass_vec, but I read this introduces quite some overhead and share_ptr should only be used as a last resort.

I also don't know if referencing like I'm attempting works out. What happens if an object in myclass_vec is deleted? Is the myclass_vec_refs vector resized by -1 since the object doesn't exist anymore or is it just pointing to bad memory?

Is it possible to emplace_back a reference in the myclass_vec_refs vector? Since this creates the object in-place I guess this doesn't work and only push_back can be used?

Sean M.
  • 595
  • 1
  • 4
  • 21
  • Why not just store an iterator in the other vector? – NathanOliver Jul 01 '16 at 12:40
  • 3
    why not store pointers instead of the allocated object ? – Pierre Emmanuel Lallemant Jul 01 '16 at 12:41
  • 3
    Why not store indexes instead? – Some programmer dude Jul 01 '16 at 12:42
  • @PierreEmmanuelLallemant because if the vector gets deleted, the pointers point to garbage. – Jossie Calderon Jul 01 '16 at 12:43
  • @JossieCalderon: yes it's why you need to update the vector to remove the pointer. don't see any problem until there. – Pierre Emmanuel Lallemant Jul 01 '16 at 12:44
  • 1
    @JossieCalderon Same goes for references, iterator that get invalidated, and indexes. – Holt Jul 01 '16 at 12:44
  • 2
    What do you actually want to do with `myclass_vec_refs`? – Holt Jul 01 '16 at 12:45
  • Can you post the code of what you tried? – Jossie Calderon Jul 01 '16 at 12:47
  • I have this `myclass_vec` defined outside a class and pass if by reference to a class which is generating a lookup table based on objects in `myclass_vec`. So the lookup table should then hold some sort of reference pointer or index to the actual object I would like to look up. – Sean M. Jul 01 '16 at 12:47
  • As @Holt says, what is the *actual problem* you want to solve with this second vector? No matter what you store in the second vector you need to keep the two vectors i sync, which creates more work for you, perhaps there are better solutions to your actual problem? Better designs? Please [read about the XY problem](http://xyproblem.info/). – Some programmer dude Jul 01 '16 at 12:48
  • @SeanM.http://stackoverflow.com/questions/922360/why-cant-i-make-a-vector-of-references – Jossie Calderon Jul 01 '16 at 12:48
  • @JoachimPileborg Probably because indexes may change when new elements are **inserted** to or removed from first vector – mvidelgauz Jul 01 '16 at 12:49
  • 2
    Maybe all your problems will go away if you just use a reference or pointer to `myclass_vec` ? If you just don't want to have copies of `myclass_vec` when you pass it around, a reference / pointer to it might be all you need. This will also fix all your subsequent issues / questions. – Fara Importanta Jul 01 '16 at 12:51

2 Answers2

1

You cannot make a vector of references. Why?

A reference must refer to an actual object at all times, and vectors by design must be able to create "empty" objects (i.e. default constructor) dynamically for you.

You can however create a vector of pointers.

If the other vector is modified in any way, your pointers will become invalid. If this is a problem to you, use a map or set instead.

Sven Nilsson
  • 1,861
  • 10
  • 11
  • 1
    It is true that you cannot have vectors of references, but your reasoning is wrong. A vector does not require the object to be default constructible. Although, some member functions of vector do (at least `resize( size_type count )` and `vector( size_type count )` are such), but you don't have to use those functions to use vector. – eerorika Jul 01 '16 at 13:05
  • 1
    @user2079303: Actually, `vector` does not require that. Or more to the point, `vector` *alone* doesn't impose a copy/move requirement. It is the methods of `vector` that actually insert/remove items that impose that requirement. The basic thing `vector` requires of `T` is Erasable via the allocator's `destroy` function. And for `std::allocator`, references are not. – Nicol Bolas Jul 01 '16 at 14:02
  • @NicolBolas oh, I made the same mistake that I was correcting in the first place. – eerorika Jul 01 '16 at 15:49
1

As answered here: Strange Template Deduction

The trick is to use std::reference_wrapper<>

#include <algorithm>
#include <iostream>
#include <vector>

template<typename container_ty_, class Comp>
auto where(container_ty_& V, Comp&& comp)
{
    using value_type = typename container_ty_::value_type;
    using reference =
    std::conditional_t<
      std::is_const<container_ty_>::value,
        std::reference_wrapper<const value_type>,
        std::reference_wrapper<value_type>
    >;

    std::vector<reference> cursor;

    for(auto& VAL : V)
        if(comp(VAL))
            cursor.push_back(VAL);

    return cursor;
}

int main(int argc, char** argv) {
    std::vector<int> tVect = {0, 5, 2, 1, 7, 9};

    //Why must std::vector<int> be passed...
    auto vec = where(tVect, [](const int& V) -> bool { return V > 5; });

    std::for_each(vec.begin(), vec.end(), [] (int& v) { std::cout << v++ << std::endl; });
    std::cout << std::endl;
    std::for_each(tVect.begin(), tVect.end(), [](const int& v) { std::cout << v << std::endl; });
}
Community
  • 1
  • 1
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142