【问题标题】:Does vector<list<T>> guarantee that element addresses stay unchanged?vector<list<T>> 是否保证元素地址保持不变?
【发布时间】:2014-10-25 02:48:28
【问题描述】:

我们都知道vector&lt;T&gt; 中元素的地址可能会随着我们追加更多元素(由于调整大小)而改变,而list&lt;T&gt; 中的元素保持在同一地址。

问题是,vector&lt;list&lt;T&gt;&gt; 呢?例如,

vector<list<T>> container;
// Insert some elements to container...
T* ptr = &(container[0].back());
// Insert more elements to container...

我们可以假设ptr 保持有效吗?

天真地,我认为它应该,因为当向量调整大小时,它应该调用list&lt;T&gt; 的移动构造函数,它不应该复制/移动单个元素。但是,我不知道标准是否能确保这一点。

【问题讨论】:

  • 列表中的元素应该是安全的,因为它应该移动。我说应该,因为我昨天在 VC++ 中发现了一个错误,移动在不应该的地方失败。我会说测试以确保。这很容易。存储一个指针。然后继续添加到向量以强制重定位。比较.data() 指针。当向量移动时,将指针地址与同一元素进行比较。
  • 有一些恼人的标准缺陷,与您的情况不完全相关,例如see here.
  • 谢谢,@KerrekSB,根据 dyp 在您的链接中的回答,似乎 C++ 标准有一个名为 LWG 2321 的提案,它将明确回答我的问题为“是”。所以我猜 current (C++11) 标准还不能完全确保它。
  • @jick 它还没有回答你的问题:它还要求vector 不复制它的任何元素。如果它在重新分配时复制元素,则对list 的移动构造函数的任何保证都不适用,因为将调用list 的复制构造函数。 vector 不应该复制它的元素,但我不知道标准是否真的说它没有。 (无论如何,我找不到它。)

标签: pointers c++11 vector stl


【解决方案1】:

您可能应该将其设为vector&lt;list&lt;T&gt;*&gt; 而不是vector&lt;list&lt;T&gt;&gt;。使用vector&lt;list&lt;T&gt;*&gt;,您可以确定包含的指针不会被更改(并且不会对内部列表进行任何重量级复制),因为它们是向量的值并且向量的值是不会被扩展逻辑改变。这比依靠复制内部列表只移动头元素而不重新分配任何剩余节点要安全得多(这也更容易理解)。反其道而行很难理解,简直是在玩火。

【讨论】:

  • 您选择原始指针而不是智能指针的任何特殊原因?
  • @hvd 这是一个好点。智能指针通常是一种更好的方法(取决于所讨论的所有权类型)。我只是想说明指针与值,这就是为什么我没有在答案中选择特定的智能指针类。
  • 好吧,就实用性而言,您可能是正确的,但我觉得如果我需要添加一层间接性只是为了安全起见,这违背了 C++ 的“精神”,除非有技术原因.此外,vector&lt;list&lt;T&gt;*&gt; 甚至vector&lt;unique_ptr&lt;list&lt;T&gt;&gt;&gt; 也并非没有陷阱:这意味着当您扩展向量时,新条目将以 NULL 指针开头,因此您始终必须记住实例化一个列表对象,这与 vector&lt;list&lt;T&gt;&gt; 编译器不同保证为我提供一个全新的列表对象。
  • C++ 11 要求 vector 移动其元素,而不是复制它们,并且还要求移动 list 不会移动其元素。这意味着list 元素不会通过向vector 添加更多项目而最终移动。此处无需使用指针。
  • 你错了。调整大小时,vector 需要使用 move_if_noexceptlist 的移动构造函数不是 noexceptlists 将被复制,而不是移动。
【解决方案2】:

对不起,没有。 std::list 的移动构造函数不是 noexceptstd::vector 在调整大小时使用了std::move_if_noexcept,这将是包含的std::lists 的副本。所有列表节点将被分配和复制。他们的地址将不稳定。

【讨论】:

  • 感谢您的回答!嗯,我用 g++ (4.7.2) 和 clang++ (3.5.0) 进行了实验,并且没有移动/复制元素(T 类型)。所以我猜这个标准并不要求 vector&lt;list&lt;T&gt;&gt; 来复制列表。无论如何,std::list 的移动构造函数不是noexcept 是否有技术原因,或者更可能是标准委员会的疏忽?
  • MS 对std::list 的实现使用动态标记节点(至少在调试中?),这意味着它们的移动构造函数实际上是在抛出异常。
  • 委员会对是否在标准不要求的地方添加noexcept 进行了一些辩论,这是一个符合标准的扩展。这是一场巨大的自行车棚辩论,我承认我不记得它是如何进行的。如果添加 noexcept 不是符合标准的扩展,那么 libstdc++ 实际上并不符合标准。只是可能需要复制列表。
猜你喜欢
  • 1970-01-01
  • 2010-10-25
  • 2019-05-09
  • 1970-01-01
  • 2010-11-05
  • 1970-01-01
  • 2013-04-30
相关资源
最近更新 更多