Design concerning std::reference_wrapper removals

1.6k Views Asked by At

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
}
1

There are 1 best solutions below

3
On

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(); });
    }
};