1

我想在 C++ 中创建一个引用列表或映射,它会在销毁时自动删除其元素。这是一个展示这个想法的结构。

class Foo;

class Bar
{
    Foo foo;
};

void main(void)
{
    std::vector<Foo> foos;

    {
        Bar bar;
        foos.push_back(bar.foo);

        // foos[0] should be the same reference as bar.foo
    }

    // bar is now destructed
    // foos.size() should be 0
}

我的代码有两个问题。当push_back()使用 std::vector 调用时,它会创建 Foo 对象的副本。这将是不可接受的,因为 的元素foos应该反映对 进行的任何更改bar.foo。其次,即使foos向量可以存储引用,Foo 对象在离开创建的范围后也不会从列表中删除bar。理想情况下,我希望 Foo 引用foos在其销毁时被删除。

在我实施自己的解决方案之前,我很想知道提供此解决方案的任何第三方库(可能是 Boost 吗?),或者我应该为此使用的任何适当技术或策略。谢谢!

4

3 回答 3

5

我认为最好的选择是使用弱指针容器。(如果您的编译器由于某种原因不支持 C++11 或 TR1,则可在 Boost 中使用。)

假设你正确地初始化了东西,当目标被破坏时,弱指针会自动失效。

这是一些示例代码,用于在弱指针容器中获取所有有效指针。

template <class T>
std::vector<std::shared_ptr<T> > MassLock(const std::vector<std::weak_ptr<T> >& weakptrs)
{
    std::vector<std::shared_ptr<T> > sharedptrs;

    for(unsigned int i=0; i<weakptrs.size(); ++i)
    {
        if (std::shared_ptr<T> temp = weakptrs.at(i).lock())
        {
            sharedptrs.push_back(temp);
        }
    }

    return sharedptrs;
}

以下是清除所有无效指针的方法。

template <class T>
struct isInvalid : public std::unary_function<T, bool>
{
    bool operator() (T rhs) { return !rhs.lock(); }
};

template <class T>
void EraseInvalid( std::vector<T>& targetlist )
{
    targetlist.erase( remove_if(targetlist.begin(), targetlist.end(), isInvalid<T>() ), targetlist.end());
}
于 2012-08-05T03:03:03.903 回答
1

如果您需要对同一个对象的多个引用,则可能需要一个“智能”指针容器,例如std::shared_ptr(如果您没有 C++11,则需要一个来自 Boost 的指针)。

于 2012-08-05T03:05:18.273 回答
0

通过使用weak_ptr(Antimony 建议)更改您的列表以保存引用,并自动删除被破坏的元素,如下所示。

首先让我们澄清一些措辞:你的标题应该是“C++ 容器,它在被破坏时自动删除对元素的引用”,因为删除一个元素实际上会破坏它,所以你不希望它在销毁时被“删除”,而是希望从容器中删除对它的引用。

std::list<std::weak_ptr<Foo>> foos;

{
    // create a new entry in the container
    const auto& iter = foos.insert(foos.end(), std::weak_ptr<Foo>());
    // create an object of type "Foo" and store it in a shared_ptr
    std::shared_ptr<Foo> foo
        (new Foo
        // set a custom deleter that actually deletes the object
        // AND erases it from the container
        , [&foos, iter](Foo* ptr)
            {
                delete ptr;
                foos.erase(iter);
            }
        );
    // set the pointer to the element into the container
    *iter = foo;
}

// the shared_ptr "foo" ran out of scope;
// as there is no further strong reference to its object
// , the custom deleter was called which has removed the entry from the container
// so foos.size() is now 0

请注意,我将容器从向量更改为列表,因为向量可能会使迭代器无效(传递给自定义删除器,请参阅是否调整向量大小使迭代器无效?)而列表不会。如果要坚持使用向量,可以使用索引作为传递给自定义删除器的元素的引用,但请注意,在 end() 之前将元素插入向量会破坏此引用。

于 2017-01-11T16:33:48.557 回答