当前位置: 首页 > 知识库问答 >
问题:

临时范围[重复]上基于范围的for循环

邓韬
2023-03-14

由于valgrind中出现了一些分段错误和警告,我发现这段代码不正确,并且在for range循环中有一些悬而未决的引用。

#include<numeric>
#include<vector>

auto f(){
    std::vector<std::vector<double>> v(10, std::vector<double>(3));
    iota(v[5].begin(), v[5].end(), 0);
    return v;
}

int main(){
    for(auto e : f()[5])
        std::cout << e << std::endl;
    return 0;
}

看起来好像开始和结束是从一个临时循环中提取的,并且在循环中丢失了。

当然,一种方法是

    auto r = f()[5];
    for(auto e : r)
        std::cout << e << std::endl;

然而,我想知道为什么for(auto e:f()[5])是一个错误,以及是否有更好的方法或某种方法来设计f,甚至容器(std::vector)来避免这个陷阱。

对于迭代器循环,更明显的是为什么会发生此问题(beginend来自不同的临时对象)

for(auto it = f()[5].begin(); it != f()[5].end(); ++it)

但是在范围循环中,就像在第一个例子中一样,似乎很容易犯这个错误。


共有2个答案

周鸿光
2023-03-14

请注意,直接使用临时作为范围表达式是可以的,它的剩余时间会被延长。但是对于f()[5]f()返回的是临时的,它是在表达式中构造的,它将在构造它的整个表达式之后被销毁。

在C 20中,您可以使用init-语句for range-based for循环来解决此类问题。

(重点矿山)

如果range\u表达式返回临时表达式,则其生存期将延长到循环结束,如绑定到rvalue引用\uu range所示,但请注意,range\u表达式内的任何临时表达式的生存期都不会延长。

这个问题可以使用初始化语句解决:

for (auto& x : foo().items()) { /* .. */ } // undefined behavior if foo() returns by value
for (T thing = foo(); auto& x : thing.items()) { /* ... */ } // OK

例如

for(auto thing = f(); auto e : thing[5])
    std::cout << e << std::endl;
曾苗宣
2023-03-14
匿名用户

我想知道为什么for(auto e:f()[5])是一个错误

我只回答这部分。原因是基于范围的for语句只是语法上的糖分,大约是:

{
    auto&& __range = f()[5]; // (*)
    auto __begin = __range.begin(); // not exactly, but close enough
    auto __end = __range.end();     // in C++17, these types can be different
    for (; __begin != __end; ++__begin) {
        auto e = *__begin;
        // rest of body
    }
}

看看第一行。发生了什么<向量上的代码>操作符[]将引用返回到该对象中,因此范围绑定到该内部引用。但是,临时文件在行尾超出了范围,破坏了它的所有内部构件,因此立即成为一个悬而未决的引用。这里没有生存期扩展,我们从不将引用绑定到临时。

在更正常的情况下,for(autoe: f()),我们会将__range直接绑定到f(),这是将引用绑定到临时,因此临时将其生命周期延长到引用的生命周期,这将是for语句的完整

为了增加更多皱纹,还有其他情况下,像这样的间接绑定仍然会延长寿命。比如说:

struct X {
    std::vector<int> v;
};
X foo();

for (auto e : foo().v) {
    // ok!
}

但是,与其试图跟踪所有这些小案例,不如像宋元耀建议的那样,使用带有初始值的新for语句。。。总是:

for (auto&& range = f(); auto e : range[5]) {
    // rest of body
}

虽然在某种程度上,这给人一种错误的安全感,因为如果你做两次,你仍然会有同样的问题...

for (auto&& range = f().g(); auto e : range[5]) {
    // still dangling reference
}

 类似资料:
  • 在临时范围上基于范围的for循环中,Barry提到以下内容不受被破坏的临时对象的影响,我测试的成员v确实存在于for循环的整个循环中(因为在for循环的整个循环中没有调用析构函数X)。解释是什么?

  • 这是从2011年开始对这个问题的扩展:基于范围的for loops和ADL 使用Visual Studio 2015,我无法使用参数依赖查找(ADL)为自定义容器创建基于范围的for循环。 我在下面用一个自定义容器做了一个非常简单的测试用例: 使用此容器和ADL,以下测试可以很好地编译: 这是应该的。我不确定ADL是否在这里得到了利用,但无论如何,它是有意义的。根据MSDN文档,我们有: 请记住以

  • 在std::unordered_映射上运行基于范围的for循环时,循环变量的类型似乎不使用引用类型: MSVC 2017、gcc 8.2和clang 7.0.0都在这里报告了一个失败的断言。与std::vector相反,它的断言不会失败,正如人们所期望的那样: 然而,在MSVC 2017和gcc 8.2上,修改局部变量r的循环将产生明显的副作用: 例如,此程序将打印(忽略订单): 我遗漏了什么?尽

  • 问题内容: 我如何让SQL重复一些基于集合的操作任意次数而不会循环?如何让SQL对一定范围的数字执行运算?我基本上是在寻找一种基于集合的for循环的方法。 我知道我可以创建一个包含整数(例如1到1000)的小表,然后将其用于该范围内的范围操作。 例如,如果我有该表,则可以选择查找数字100-200的总和,如下所示: 有任何想法吗?我有点在寻找适用于T-SQL的东西,但是任何平台都可以。 问题答案:

  • 我对C很陌生,现在就在做中学习。在课堂材料中,我有以下功能: 几分钟前,我像这样使用了普通for循环:

  • 本文向大家介绍C#范围和重复,包括了C#范围和重复的使用技巧和注意事项,需要的朋友参考一下 示例 的Range和Repeat静态方法Enumerable可用于生成简单序列。 范围 Enumerable.Range() 给出给定起始值和计数的整数序列。 .NET Fiddle上的实时演示 重复 Enumerable.Repeat() 在给定一个元素和所需重复次数的情况下,生成一系列重复元素。 .NE