std::vector::swap 是否会使迭代器无效?

发布于 2024-10-01 08:07:45 字数 572 浏览 1 评论 0原文

如果我交换两个向量,它们的迭代器是否仍然有效,现在只是指向“其他”容器,或者迭代器是否会失效?

也就是说,给定:

using namespace std;
vector<int> x(42, 42);
vector<int> y;
vector<int>::iterator a = x.begin(); 
vector<int>::iterator b = x.end();

x.swap(y);

// a and b still valid? Pointing to x or y?

std 似乎没有提到这一点:

[n3092 - 23.3.6.2]

void swap(向量& x);

效果: 交换内容和容量() *this 与 x 的那个。

请注意,由于我使用的是 VS 2005,所以我也对迭代器调试检查等的效果感兴趣。(_SECURE_SCL)

If I swap two vectors, will their iterators remain valid, now just pointing to the "other" container, or will the iterator be invalidated?

That is, given:

using namespace std;
vector<int> x(42, 42);
vector<int> y;
vector<int>::iterator a = x.begin(); 
vector<int>::iterator b = x.end();

x.swap(y);

// a and b still valid? Pointing to x or y?

It seems the std mentions nothing about this:

[n3092 - 23.3.6.2]

void swap(vector<T,Allocator>& x);

Effects:
Exchanges the contents and capacity()
of *this with that of x.

Note that since I'm on VS 2005 I'm also interested in the effects of iterator debug checks etc. (_SECURE_SCL)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

凡尘雨 2024-10-08 08:07:45

交换的行为在 C++11 中已得到相当程度的澄清,很大程度上是为了允许标准库算法使用参数相关查找 (ADL) 来查找用户定义类型的交换函数。 C++11 添加了一个可交换概念(C++11 §17.6.3.2[swappable.requirements])以使此合法(且必需)。

C++11 语言标准中解决您问题的文本是容器要求 (§23.2.1[container.requirements.general]/8) 中的以下文本,它定义了交换的行为 容器的成员函数:

在交换之前引用一个容器中的元素的每个迭代器都应在交换之后引用另一个容器中的相同元素。

未指定在交换之前具有值 a.end() 的迭代器在交换之后是否具有值 b.end()

在您的示例中,a 在交换后保证有效,但 b 则不然,因为它是一个结束迭代器。 §23.2.1/10 的注释中解释了末端迭代器不保证有效的原因:

[注意:end()迭代器不引用任何元素,因此它可能是
无效。 --注结束]

这与 C++03 中定义的行为相同,只是进行了实质性澄清。 C++03 的原始语言位于 C++03 §23.1/10:

没有 swap() 函数会使引用被交换容器的元素的任何引用、指针或迭代器无效。

在原文中并不是很明显,但是短语“指向容器的元素”非常重要,因为 end() 迭代器不指向元素。

The behavior of swap has been clarified considerably in C++11, in large part to permit the Standard Library algorithms to use argument dependent lookup (ADL) to find swap functions for user-defined types. C++11 adds a swappable concept (C++11 §17.6.3.2[swappable.requirements]) to make this legal (and required).

The text in the C++11 language standard that addresses your question is the following text from the container requirements (§23.2.1[container.requirements.general]/8), which defines the behavior of the swap member function of a container:

Every iterator referring to an element in one container before the swap shall refer to the same element in the other container after the swap.

It is unspecified whether an iterator with value a.end() before the swap will have value b.end() after the swap.

In your example, a is guaranteed to be valid after the swap, but b is not because it is an end iterator. The reason end iterators are not guaranteed to be valid is explained in a note at §23.2.1/10:

[Note: the end() iterator does not refer to any element, so it may be
invalidated. --end note]

This is the same behavior that is defined in C++03, just substantially clarified. The original language from C++03 is at C++03 §23.1/10:

no swap() function invalidates any references, pointers, or iterators referring to the elements of the containers being swapped.

It's not immediately obvious in the original text, but the phrase "to the elements of the containers" is extremely important, because end() iterators do not point to elements.

绻影浮沉 2024-10-08 08:07:45

交换两个向量不会使迭代器、指针和对其元素的引用无效(C++03、23.1.11)。

通常,迭代器将包含其容器的知识,并且交换操作为给定的迭代器维护这一点。

在 VC++ 10 中,向量容器是使用 中的结构进行管理的,例如:

struct _Container_proxy
{   // store head of iterator chain and back pointer
    _Container_proxy()
    : _Mycont(0), _Myfirstiter(0)
    {   // construct from pointers
    }

    const _Container_base12 *_Mycont;
    _Iterator_base12 *_Myfirstiter;
};

Swapping two vectors does not invalidate the iterators, pointers, and references to its elements (C++03, 23.1.11).

Typically the iterator would contain knowledge of its container, and the swap operation maintains this for a given iterator.

In VC++ 10 the vector container is managed using this structure in <xutility>, for example:

struct _Container_proxy
{   // store head of iterator chain and back pointer
    _Container_proxy()
    : _Mycont(0), _Myfirstiter(0)
    {   // construct from pointers
    }

    const _Container_base12 *_Mycont;
    _Iterator_base12 *_Myfirstiter;
};
苍暮颜 2024-10-08 08:07:45

至于Visual Studio 2005,我刚刚测试过。
我认为它应该始终有效,因为 vector::swap 函数甚至包含交换所有内容的显式步骤:

 // vector-header
    void swap(_Myt& _Right)
        {   // exchange contents with _Right
        if (this->_Alval == _Right._Alval)
            {   // same allocator, swap control information

 #if _HAS_ITERATOR_DEBUGGING
            this->_Swap_all(_Right);
 #endif /* _HAS_ITERATOR_DEBUGGING */
 ...

迭代器指向现在交换的向量对象中的原始元素。 (即 w/rg 到 OP,它们首先指向 x 中的元素,交换后它们指向 y 中的元素。)

请注意,在 n3092 草案中要求§23.2.1/9 中列出:

每个迭代器都引用一个
之前的一个容器中的元素
交换应引用相同的元素
交换后在另一个容器中。

As for Visual Studio 2005, I have just tested it.
I think it should always work, as the vector::swap function even contains an explicit step to swap everything:

 // vector-header
    void swap(_Myt& _Right)
        {   // exchange contents with _Right
        if (this->_Alval == _Right._Alval)
            {   // same allocator, swap control information

 #if _HAS_ITERATOR_DEBUGGING
            this->_Swap_all(_Right);
 #endif /* _HAS_ITERATOR_DEBUGGING */
 ...

The iterators point to their original elements in the now-swapped vector object. (I.e. w/rg to the OP, they first pointed to elements in x, after the swap they point to elements in y.)

Note that in the n3092 draft the requirement is laid out in §23.2.1/9 :

Every iterator referring to an
element in one container before the
swap shall refer to the same element
in the other container after the swap.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文