【问题标题】:What does end() refere to in the following example? [duplicate]以下示例中的 end() 指的是什么? [复制]
【发布时间】:2022-01-03 15:05:22
【问题描述】:

我有一个集合列表:

std::list<std::set<int>> nn = {{1,2},{4,5,6}};

我想打印出 end() 所指的元素:

for (auto el : nn){
        std::cout << *el.end() << std::endl;
    }

我得到的结果是: 23.

我不知道这些值是从哪里来的。有人可以帮我吗?

【问题讨论】:

  • 这些值来自未定义的行为
  • 这是未定义的行为 - 无效代码。
  • end() 没有引用任何元素,取消引用它是非法的。如果你想要最后一个元素使用*rbegin()
  • end() 不是容器的元素。它是列表末尾之后的第一个位置。
  • en.cppreference.com/w/cpp/container/set/end "充当占位符;尝试访问它会导致未定义的行为"

标签: c++ list iterator set


【解决方案1】:

问题 1

end() 指的是什么

回答

end()std::setpublic member function,它返回一个 迭代器set 容器中的过去元素。

问题 2

我不知道这些值是从哪里来的。

回答

你写的时候:

std::cout << *el.end() << std::endl;//this is undefined behavior

在上述语句中,您将取消引用 end() 成员函数返回的迭代器。

但请注意,如果我们取消引用此成员函数返回的迭代器,则会得到未定义的行为

未定义的行为意味着任何事情1都可能发生包括但不限于给出您预期输出的程序。但是永远不要依赖(或根据)具有未定义行为的程序的输出。


1有关未定义行为的更准确的技术定义,请参阅this,其中提到:对程序的行为没有限制 .

【讨论】:

    【解决方案2】:

    不允许取消引用end() 迭代器。这样做会导致未定义的行为。它不引用容器的任何元素,而是在最后一个元素之后

    end()“点”在最后一个元素之后的原因,是需要区分空容器。如果end() 指的是最后一个元素,begin() 指的是第一个元素,那么如果begin() == end() 则意味着容器中有一个元素,我们无法区分空容器的情况。

    对于支持它的容器,要访问容器的最后一个元素,您可以使用.back(),它将返回一个引用,而不是一个迭代器。但这仅在有最后一个元素时才允许,即容器不为空时。否则,您将再次出现未定义的行为。因此,如有必要,请先检查.empty()

    std::set 没有back() 成员,并不是真的打算以这种方式使用,但如果你真的想访问最后一个元素,它不是构造函数初始化列表中的最后一个元素,而是元素的&lt; 顺序中的最后一个元素,那么您可以使用std::prev(el.end())el.rbegin()(“反向开始”),这将为您提供最后一个元素的迭代器。同样,仅当容器不为空时才允许取消引用此迭代器。 (对于std::prev,即使容器为空,也不允许形成迭代器本身。)


    未定义的行为意味着您将无法保证程序的行为。它可以在一次运行中输出一些东西,而在另一次运行中输出其他东西。它也可以不输出任何内容等。

    没有要求你会得到你看到的输出。例如,当前使用 libc++ 作为标准库实现的 x86_64 Clang 编译(有或没有优化)一个打印两次 0 的程序。 https://godbolt.org/z/nWMss1fqe

    实际上,假设编译器没有利用未定义的行为进行优化,从而彻底改变“预期”程序流程的程序,根据标准库的实现,您可能会阅读一些内部标准库中std::set 实现的内存,如果间接指向不可访问的内存或偶然(没有保证)引用容器中的其他值,则会出现分段错误。

    【讨论】:

      猜你喜欢
      • 2015-06-18
      • 1970-01-01
      • 1970-01-01
      • 2016-06-13
      • 2015-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-15
      相关资源
      最近更新 更多