当使用命名局部变量与纯右值作为
std::ranges::dangling
算法的参数时,我无法理解类型何时推导出 std::ranges::sort
。例如,我有一个将 prvalue
返回到标准容器的函数,例如 std::vector,我直接将其用作 std::ranges::sort
的参数,那么当我尝试取消引用时,我预计会收到有关 std::ranges::dangling
的编译错误迭代器,这就是我得到的:
#include <vector>
#include <algorithm>
auto get_data(){
return std::vector<int>{1, 2, 99, 5, 9, 4};
}
auto get_sorted(){
return std::ranges::sort(get_data());
}
int main(){
auto it = get_sorted();
*(it-1); //Compiler Error because it is a std::ranges::dangling iterator
}
但是,如果我稍微更改上面的
get_sorted
函数以首先捕获命名变量中的向量,然后使用它来返回 std::ranges::sort
的结果,那么即使在 main
中,我也不会得到悬空迭代器尽管在函数 get_sorted
返回后,命名变量中分配的向量应该已被销毁:
auto get_sorted(){
auto vec = get_data();
return std::ranges::sort(vec);
}
int main(){
auto it = get_sorted();
*(it-1); //Okay result = 99
}
即使我将
get_sorted
更改为使用本地声明的基于命名变量的容器,我也会得到这样的行为:编译器不会抱怨在其调用者中取消引用悬空迭代器(例如 main
函数)。
//doesn't return a std::ranges::dangling
auto get_sorted(){
std::vector<int> vec{1, 2, 99, 5, 9, 4};
return std::ranges::sort(vec);
}
当我将纯右值向量传递给
std::ranges::sort
算法时,我再次得到预期的 std::ranges::dangling
//returns a std::ranges::dangling
auto get_sorted(){
std::vector<int> vec{1, 2, 99, 5, 9, 4};
return std::ranges::sort(std::vector<int>{1, 2, 99, 5, 9, 4});
}
对于编译器没有收到有关
std::ragnes::dangling
的错误的情况,当我使用 fSanitize=address
选项进行编译时,我确实观察到运行时错误,这可能是因为在 get_sorted
函数内的命名变量中分配的向量后一个函数返回后就超出范围。
但是我想了解为什么在函数中使用命名变量会更改
get_sorted
函数的返回类型,并可能提供有关如何正确使用临时和纯右值容器以尽可能获取 std::ranges::dangling
的指南。
实际上我想我很确定这是因为代码创建了超出范围的临时对象。 https://en.cppreference.com/w/cpp/ranges/dangling上的示例代码完美地展示了您正在做的事情,产生了这种行为。
代码触发与示例中相同的静态断言:
static_assert(std::is_same_v<std::ranges::dangling, decltype(dangling_iter)>);
。
当源超出范围时,这将产生悬空类型/排序操作后将变得不可访问。
您可能仍然可以欺骗这个安全网进行不安全的操作,正如您通过创建一个临时命名变量,然后返回排序结果(并且向量被破坏)所示的那样 - 代码正在尝试访问已释放的内存(这是一个很大的问题) -不)。
局部变量在其当前作用域之后将变得不可用,这意味着任何引用都将变得悬空。 std::ranges 库正在尽最大努力保护您在简单情况下(例如您的第一个情况)不这样做。
为了使代码正常工作,您必须在任何迭代器操作期间保持向量可用:
auto get_data(){
return std::vector<int>{1, 2, 99, 5, 9, 4};
}
auto get_sorted(std::vector<int>& data){
return std::ranges::sort(data);
}
int main(){
auto data = get_data();
auto it = get_sorted(data);
*(it-1);
}