const string& 构造函数和模板化 std::set find 的分段错误

2024-01-15

以下代码遇到了段错误const string&构造函数,并以 0 退出string_view构造函数。我知道const string&这不是最好的方法。但根据我的理解,如果没有优化,临时string是由构造而成const char*,然后它的值被复制到Person构造函数被销毁之前。构造函数对我来说看起来有效。对于查找部分,set::find (string_view)将根据需要使用定义的 less 运算符。我没有看到这里有什么问题。我可以使用 g++-10 或 VS2022 重现该问题。

#include <set>
#include <iostream>
#include <string>
#include <string_view>
using namespace std;

struct Person{
    string name;
    Person(const string& s):name{s}{}
    //Person(string_view s):name{s}{}
    bool operator<(string_view s)const{
        return name<s;
    }
    bool operator<(const Person& o)const{
        return name<o.name;
    }
};
bool operator<(string_view s,const Person& p){
    return s<p.name;
}
set<Person,less<>>s;

int main(){
    s.emplace("hello");
    string_view hel="hel";
    auto res=s.find(hel);
}

gdb 为我提供了有关崩溃的以下信息:

Program received signal SIGSEGV, Segmentation fault.
0x000000000800280c in std::char_traits<char>::copy (__s1=0x7fffff7ef1c0 "\340\361~\377\377\177", __s2=0x7fffff7ef230 "hello",
    __n=<error reading variable: Cannot access memory at address 0x7fffff7eeff8>) at /usr/include/c++/10/bits/char_traits.h:401
401           copy(char_type* __s1, const char_type* __s2, size_t __n)

您的独立式operator<递归地调用自身(并且无限地)。这是因为没有内置的<比较一个的运算符string_view to a string,还有is隐式转换自string to const Person&.

虽然也有一个隐式转换string to string_view,因为函数本身的作用域/命名空间中有一个可用的转换,该转换是通过对两个操作数类型进行参数相关的查找找到的,而不是任何其他转换(感谢 Sam Varshavchik 指出了这一点)。

因此,在该函数体内,右侧操作数<比较被转换为const Person&,该函数因此调用自身。

要解决此问题,请将操作数转换为相同的 STL 类型;要么到 2string_view操作数,像这样:

bool operator<(string_view s, const Person& p)
{
    return s < string_view(p.name);
}

或 2string操作数,像这样:

bool operator<(string_view s, const Person& p)
{
    return string(s) < p.name;
}

注意:这不是一个特别容易发现的问题。但是,打开(完整)编译器警告可能会有所帮助。对于你的原始代码,MSVC 给了我这个:

警告 C4717:'operator

并且 clang 显示:

警告:通过此函数的所有路径都将调用自身 [-Winfinite-递归]

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

const string& 构造函数和模板化 std::set find 的分段错误 的相关文章

随机推荐