我是不是保证在移动向量后指向 std::vector 元素的指针有效?
Posted
技术标签:
【中文标题】我是不是保证在移动向量后指向 std::vector 元素的指针有效?【英文标题】:Am I guaranteed that pointers to std::vector elements are valid after the vector is moved?我是否保证在移动向量后指向 std::vector 元素的指针有效? 【发布时间】:2014-10-10 10:32:43 【问题描述】:考虑这个例子:
std::vector<int> v1 = 1, 2, 3 ;
const int* i = &v1[1];
std::vector<int> v2(std::move(v1));
std::cout << *i << std::endl;
尽管在许多 STL 实现中这可能会起作用,但我是否保证在移动 std::vector
时不会执行重新分配,并且支持 v2
的内部缓冲区与过去相同v1
的?我无法在 Internet 和标准本身上找到此信息。
【问题讨论】:
如果标准没有说明它,那么我猜它是依赖于实现的。 N3797 中的表 99 说X(rv)
,即从右值构造容器,必须具有 constant 复杂性(相对于 linear复制构造),我认为我们可以从中推断出元素在移动后必须驻留在相同的内存位置。但是并不一定意味着迭代器仍然有效
我认为在这种情况下不能保证,但如果你改为使用std::vector<int> v2; v2.swap(v1);
,那么它肯定是。 (23.2.1/10)
这是LWG open issue 2321,另见home.roadrunner.com/~hinnant/iterator.html
@gd1 来自 LWG 2321:“容器的无移动构造函数 [...](array
除外)会使任何引用的引用、指针或迭代器无效源容器的元素。”
【参考方案1】:
这是LWG open issue 2321 [强调我的]
应该(通常)需要移动容器来保留迭代器
[...]
[斯蒂芬·T·拉瓦维(Stephan T. Lavavej)] 23.2.1 [container.requirements.general]/10 说,除非另有说明,否则“没有 swap() 函数会使任何引用、指针、 或引用容器元素的迭代器 交换了。 [注意:end() 迭代器不引用任何元素,所以 它可能会失效。 — 结束注]"。但是,移动构造函数和 移动赋值运算符没有被赋予类似的失效 保证。 保证需要几个例外,所以我不 相信像 /11 这样的笼统语言“除非另有说明 (明确地或通过根据其他定义一个函数 函数),调用容器成员函数或传递 容器作为库函数的参数不应无效 迭代器或更改该容器内对象的值。” 适用。
[2014-02-13 伊萨夸]
就意图达成一般性协议、几个措辞和附加段落。
STL 提供更新的措辞。 移至打开。
建议的解决方案:
[...]
容器(
array
除外)的无移动构造函数 [...] 会使引用源容器元素的任何引用、指针或迭代器无效。 [注意:end()
迭代器不引用任何元素,因此它可能会失效。 ——尾注]
所以,这是一个悬而未决的问题,对其基本解决方案已达成普遍共识(指针不应因移动而失效)。但是,它还没有正式被接受(还没有?)作为一个缺陷。据我所知,所有主要的实现在移动构造时都不会使指针无效,这似乎是一个普遍(隐式)提供的保证。
【讨论】:
谢谢。在我的实际场景中,我很容易通过使用swap
来规避这个问题,我可能会继续使用该解决方案。不过,这些信息非常有用,很高兴知道有些人正在解决这类问题。【参考方案2】:
cppreference.com 声明:
... 可以选择(但不是必需的)移动由 论据...
看起来std::move
只是向库暗示可以通过转移所有权进行优化,但是否进行优化取决于库。
这意味着您应该假设所有指向元素的指针在移动后都无效。
【讨论】:
这完全忽略了std::move
的意思。是的,std::move
有效地充当了对其他功能的提示。它允许使用vector(vector&&)
构造函数。 move
对该构造函数没有任何要求,但标准有,that 就是问题所在。
'如果参数标识资源拥有对象,这些重载可以选择但不是必需的,以移动参数持有的任何资源。它说没有必要在移动对象中移动所有资源。我想知道移动构造函数是否不想移动对象中的资源(并进行优化),为什么它首先要有移动构造函数?
@MohammadRB 可能是因为它是由编译器自动生成的,可能是因为该类必须与具有更多功能移动构造函数的实现兼容,可能该类甚至没有 有一个移动构造函数,即使使用了std::move
,最终还是使用了C(const C&)
复制构造函数。
@MohammadRB std::vector
的大多数实现不移动资源对象(容器的每个元素);他们只是交换一个指针(移动所有权)。
这很有趣也很有用,谢谢。我可能最终会使用swap
,因为它显然保证了迭代器(因此,我猜是指针)的有效性。以上是关于我是不是保证在移动向量后指向 std::vector 元素的指针有效?的主要内容,如果未能解决你的问题,请参考以下文章