【问题标题】:How to properly keep track of addresses using STL?如何使用 STL 正确跟踪地址?
【发布时间】:2013-11-28 11:36:08
【问题描述】:

背景

我有一个对象向量和一个按名称(字符串)指向这些对象的索引(映射)。 在我的例子中,向量只会增长(项目永远不会被删除)。

我不知道这个

struct Foo { };
std::vector<Foo>            v;
std::map<std::string,Foo*>  m;   // addresses are &v[0], &v[1], etc...

因为当我将项目添加到 v 时,如果 v 被重新分配,m 中的旧映射可能会失效。

问题

如果我通过std::unique_ptr&lt;&gt; 添加额外的抽象级别,m 是否应该重新分配v

struct Foo { };
std::vector<std::unique_ptr<Foo>>  v;
std::map<std::string,Foo*>         m;   // addresses are v[0].get(), v[1].get(), etc...

由于复制省略,我认为答案是肯定的,但我不确定。

【问题讨论】:

  • 除非您确实需要将向量中的项目存储在连续的内存区域中,否则您可能需要查看std::deque。指向双端队列(或迭代器)中元素的指针永远不会失效(当然,除非元素被删除)。
  • std::map&lt;std::string,int&gt; 怎么样,其中整数是向量的索引。那么重新分配就没有问题了。
  • @john 是的,我考虑过索引/间接 - 我只是想知道上述解决方案是否可以解决问题
  • @JoachimPileborg 我喜欢std::deque 的想法-谢谢!
  • 您使用 std:: 暗示 C++ 标准库,而不是 STL。

标签: c++ memory-management c++11 stl


【解决方案1】:

简短回答:是的,但与copy elision无关

一些细节

在第一种情况下,为向量分配的内存是一个连续的 Foo 数组。 正如您所暗示的,在增大向量时,如果当前数组的容量不够大,则会分配一个新数组,并且索引中的指针仍指向旧地址。

// let x be sizeof(Foo)

Adresses       10     10+x   10+2x
Type        [  Foo |  Foo |  Foo ]

重新分配发生

Adresses       30     30+x   30+2x   30+3x
Type        [  Foo |  Foo |  Foo  |  Foo ]

如您所见,第一个Foo 对象在地址 10 处不再存在。

第二种方法

使用第二种方法,您不是在向量中按值存储 Foo,而是通过指针。假设您在空闲存储中为指向的 Foo 对象正确分配了内存,则该对象不需要移动。 当 Vector 增长并需要重新分配时,它将分配一个新的(唯一)指针数组,指向您的 Foo 对象,unique_ptr 的地址将改变(如果需要,您的 Foo**),对象保持在完全相同的地址和以前一样(Foo* 是一样的)。

// let y be sizeof(Foo*)

Adresses       10     10+y   10+2y  .. 50   ..  60  ..  90          
Type        [  Foo* | Foo* | Foo* ]   [Foo]    [Foo]   [Foo]
Value       (  50     60     90   )

重新分配发生

Adresses       30     30+y   30+2y  30+3y   .. 50   ..  60  ..  90  ..  110          
Type        [  Foo* | Foo* | Foo*  | Foo* ]   [Foo]    [Foo]   [Foo]   [Foo]
Value       (  50     60     90      110   )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-05-17
    • 1970-01-01
    • 2020-03-18
    • 2014-12-29
    • 1970-01-01
    • 1970-01-01
    • 2019-10-08
    • 1970-01-01
    相关资源
    最近更新 更多