理解带有临时和纯右值参数的 std::ranges::sort 的返回类型

问题描述 投票:0回答:1

当使用命名局部变量与纯右值作为

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
的指南。

c++ sorting c++20 std-ranges prvalue
1个回答
0
投票

实际上我想我很确定这是因为代码创建了超出范围的临时对象。 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);
}
© www.soinside.com 2019 - 2024. All rights reserved.