由于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)来避免这个陷阱。
对于迭代器循环,更明显的是为什么会发生此问题(
begin
和end
来自不同的临时对象)
for(auto it = f()[5].begin(); it != f()[5].end(); ++it)
但是在范围循环中,就像在第一个例子中一样,似乎很容易犯这个错误。
请注意,直接使用临时作为范围表达式是可以的,它的剩余时间会被延长。但是对于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;
我想知道为什么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