【问题标题】:How to properly work with vectors of pointers?如何正确使用指针向量?
【发布时间】:2018-03-19 16:51:25
【问题描述】:

如果我有一个对象向量,例如:

std::vector<Foo> foos;

for(int i = 0; i < 10; i++) {
    foos.push_back(Foo());
}

假设我用不同的Bars 来区分它们,每个都有一个Foos 的向量:

std::vector<Bar> bars;

bars.push_back(Bar());
bars.push_back(Bar());

for(int i = 0; i < 5; i++)
    bars.at(0).addFoo(foos.at(i));

for(int i = 5; i < 10; i++)
    bars.at(1).addFoo(foos.at(i));

如果我现在这样做,例如foos.at(0).setValue(1)bars.at(0).getFoo(0).getValue() 不会是 1,所以我必须创建指针:

std::vector<Bar> bars;

bars.push_back(Bar());
bars.push_back(Bar());

for(int i = 0; i < 5; i++)
    bars.at(0).addFoo(&foos.at(i));

for(int i = 5; i < 10; i++)
    bars.at(1).addFoo(&foos.at(i));

bars.at(0).getFoo(0).getValue() 现在将返回 1。

但是如何正确清理这些指针呢?

  • 如果我这样做foos.pop_back(),我怎样才能自动删除bars.at(1) 中的最后一个Foo 指针?因为在我的程序中,我有时不知道 bars 向量中指向确切对象的指针在哪里。
  • 如果我这样做bars.at(1).removeLastFoo(),对象当然会(也应该)在foos 中保持活力。 removeLastFoo() 会删除Foos 的Bars 向量的最后一个指针并弹出它吗?
  • 如果我执行bars.pop_back,我是否必须在Bars 析构函数中写入以删除其中的每一个指针?

如果我忘记了什么,请告诉我。

或者有没有更优雅的方式(我实际上不喜欢使用指针,但我看不到其他方式)能够在不同的位置看到相同的变化?

【问题讨论】:

  • 你没有,这些指针不稳定。您可以考虑改用std::list
  • @user0042 是什么原因?我会在哪里使用它?而不是Foos 的vectorBars 的vectorFoos 内部的vector Bar 类?
  • 它们不稳定,因为(连续数组的)内存管理受std::vector的控制。

标签: c++ pointers object vector memory-management


【解决方案1】:

最后我通过不添加任何对象或指向bars 的指针解决了我的问题。我修改了 Bar 类,而不是添加 Foo 对象或指针,而是从原始 foos 向量中添加了它们的索引。

// create foos
std::vector<Foo> foos;

for(int i = 0; i < 10; i++) {
    foos.push_back(Foo());
}


// create bars
std::vector<Bar> bars;

bars.push_back(Bar());
bars.push_back(Bar());

for(int i = 0; i < 5; i++)
    bars.at(0).addFooIndex(i);

for(int i = 5; i < 10; i++)
    bars.at(1).addFooIndex(i);


// print & calculate
foos.at(0).setValue(1);
std::cout << foos.at(bars.at(0).getFirstIndex()).getValue() << std::endl; // prints 1

foos.at(bars.at(0).getFirstIndex()).setValue(2);
std::cout << foos.at(0).getValue() << std::endl; // prints 2

【讨论】:

    【解决方案2】:

    如果您使用的是 C++11,则可以使用 shared_ptrweak_ptr 的组合:

    std::vector<std::shared_ptr<Foo>> foos;
    

    在 Bar 内部你会有一个 weak_ptr 的向量:

    std::vector<std::weak_ptr<Foo>> foos_inside_bar;
    
    
    for(int i = 0; i < 5; ++i) {
        std::weak_ptr<Foo> weak_foo_ptr = foos.at(i);
        bars.at(0).addFoo(weak_foo_ptr);
    }
    

    如果您执行foos.pop_back(),则foos 中的shared_ptr 将被删除,最后一个weak_ptr 将被删除expire。 如果您删除bars 中的weak_ptrfoos 中的shared_ptr 将保持活动状态。

    【讨论】:

    • 正常工作。我不喜欢的一件事是,在addFoo 中,您应该首先搜索过期的weak_ptrs 并删除它们,这样您的向量就不会因为过期的指针而变得越来越长。但只要不需要很长时间,我就可以接受
    • 这也是我关心的问题,但是当foos.pop() 完成时,我找不到删除过期指针的正确方法。至少在不把代码弄乱的情况下是这样的:/
    猜你喜欢
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-11
    • 2018-08-09
    • 2018-03-22
    相关资源
    最近更新 更多