1

I am trying to use std::reference_wrapper on all elements of another vector. But when I delete the original element, I want to automatically delete the element in the vector of references. I did some workarounds but they're ugly. Any suggestions?

#include <iostream>
#include <list>

struct A
{
    A(int x) : x(x){}
    int x;
};
std::list<std::reference_wrapper<A>> listRef;

struct B
{
    std::list<A> l;
    B()
    {
        l.emplace_back(42);
        listRef.emplace_back(l.back());
    }
    void foo()
    {
        customRemove(l.back());
    }
    void customRemove(const A & obj)
    {
        //l.remove(obj); // Error: binary '==': no operator found which takes 
        //a left-hand operand of type 'A' (or there is no acceptable conversion)
        // so I did
        l.remove_if([&](const A & obj2) { return &obj == &obj2; });
        // is there a way to automatically remove dangling references?
        listRef.remove_if([&](const A & obj2) { return &obj == &obj2; });
    }
};

int main()
{
    B b;
    std::cout << listRef.size() << '\t' << b.l.size() << '\n'; // prints 1  1
    b.foo();
    std::cout << listRef.size() << '\t' << b.l.size() << '\n'; // prints 0  0
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
user1000
  • 79
  • 2
  • 9

1 Answers1

0

In short: don't do this. There isn't any benefit of storing std::reference_wrapper<A> in your list over just having a list of raw pointers.

A better approach would be to store std::shared_ptr in l and then std::weak_ptr in listRef. Then if you end up with dangling references in listRef you can test whether the object still exists before using it:

std::list<std::weak_ptr<A>> listRef;

struct B
{
    std::list<std::shared_ptr<A>> l;
    B()
    {
        l.emplace_back(new A(42));
        listRef.emplace_back(l.back());
    }
    void foo()
    {
        customRemove(l.back());
    }
    void customRemove(std::shared_ptr< A > obj)
    {
        l.remove(obj);
        obj.reset();
        listRef.remove_if([&](const std::weak_ptr<A> & obj2) { return obj2.expired(); });
    }
};
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • One use is to pass references though interfaces that need to copy values, for example you need to use it with `std::bind` when wrapping a function that takes a non-const reference. There is an example here https://en.cppreference.com/w/cpp/utility/functional/reference_wrapper which would be slightly more verbose if using pointers. In your use case its not that raw pointers are preferable to `std::reference_wrapper` it's more that both are equally dangerous (`std::reference_wrapper` just stores raw pointers internally). – Alan Birtles Sep 21 '18 at 14:15
  • If I don’t remove the weak_ptr will it be automatically freed when I try to dereference it? – user1000 Sep 22 '18 at 10:37
  • the `weak_ptr` doens't keep the object alive, when you call `lock()` it will return a null `shared_ptr` if the object has already been freed. The `weak_ptr` itself won't be freed until you remove it from the list and is probably the size of 2 pointers. – Alan Birtles Sep 22 '18 at 11:59