将 nullptr 传递给我的重载函数会导致运行时错误

Passing a nullptr to my overloaded function causes a runtime error

提问人:Itachi Uchiwa 提问时间:4/7/2021 最后编辑:Remy LebeauItachi Uchiwa 更新时间:4/8/2021 访问量:258

问:

为了更多地了解使用指令和函数重载,我尝试了这个程序:

namespace ns{
    void f(int){cout << "int\n";}
    void f(double){cout << "double\n";}
    void f(std::string){cout << "string\n";}
    struct Foo{};
}

void f(ns::Foo const&){
    cout << "ns::Foo\n";
}

namespace bin{
    void f(int*){
        std::cout << "bin::f(int*)\n";
    }
}


int main(){

    using namespace ns;
    //using namespace bin;

    f(7); // int
    f(7.5); // double

    f(ns::Foo{}); // ns::Foo

    try{
        f(nullptr);
    }
    catch(std::exception const& e){
        std::cout << e.what() << std::endl;
    }
}

当我运行该程序时,它工作正常,除了导致运行时错误的最后一次调用:f(nullptr)

int
double
ns::Foo
basic_string::_M_construct null not valid

如果我取消注释命名空间的指令,那么代码就可以正常工作。usingbin

using namespace bin;

输出:

int
double
ns::Foo
bin::f(int*)
C++ 重载 using 指令

评论

2赞 tadman 4/7/2021
void f(std::string)将错误地尝试转换为 .char*std::string
0赞 user4581301 4/7/2021
不幸的是,你可以用 做同样的事情。任何其他数字都会被编译器捕获为非法的整数到字符串的转换,但 和 0 之间的历史关系在这里会受到阻碍。f(0)NULL
2赞 engf-010 4/7/2021
当使用命名空间 bin 时,你的 f(int*) 更好匹配(无转换),然后 string( const char* ) 错误的事实并不重要。

答:

4赞 Remy Lebeau 4/7/2021 #1

当被注释掉时,只有 1 个版本可用,可以将 作为输入。 不能隐式转换为 或 ,因此被排除在外。但可以从 构造 ,并且可以隐式转换为 ,因此编译器可以构造一个临时对象来传递给 。但是,从 null 构造 a 是未定义的行为,因此运行时错误(顺便说一句,这不能保证,因为行为是未定义的,所以任何事情都可能发生)。using namespace bin;f()nullptrnullptrintdoublens::f(int)ns::f(double)std::stringconst char*nullptrconst char*std::stringns::f(std::string)std::stringconst char*

当未注释掉时,有 2 个可用版本可以将 作为输入。 比 更好匹配,因为可以隐式转换为 ,因此无需构造临时对象,因此编译器选择调用 而不是 。using namespace bin;f()nullptrbin::f(int*)ns::f(std::string)nullptrint*bin::f(int*)ns::f(std::string)

评论

0赞 Itachi Uchiwa 4/8/2021
好的,谢谢你。所以你的意思是采用常量字符串的构造函数总是取消引用该参数 ()?所以我认为该字符串构造函数检查其参数(指针)中的空终止符作为字符串末尾的歌唱,这就是为什么它取消引用它甚至为 null 的原因?因此,该 ctor 的可能实现 r 重载是提供一个单独的参数作为大小。在这一点上,我们可以决定取消引用或不引用该指针。(如果 0 不取消引用,否则执行)?我的想法正确吗?std::stringchar const*
0赞 Itachi Uchiwa 4/8/2021
并且该构造函数采用指向字符串 () 的单个指针,并且不允许通过 Copy-Initialization 对 const char* 进行隐式转换 (char const* to std::string),例如?std::string(char const*);explicitstd::string str = "Hi there!";
1赞 Remy Lebeau 4/8/2021
构造函数在给定 null 指针时执行的操作是未定义的。它可以取消引用指针,也可以不取消引用。这要由执行部门来决定。如果要避免此问题,可以提供重载并自行检查 null。但是,如果使用 ,则会出现歧义错误,除非您显式将 to 类型转换为 。std::string(const char*)ns::f(const char*)using namespace bin;nullptrchar*int*
0赞 Itachi Uchiwa 4/8/2021
所以你的意思是实现负责如何初始化从指针到 char 的类的数据成员?std::stringchar const*
1赞 Remy Lebeau 4/8/2021
是的,标准没有说明构造函数必须做什么,因此实现可以做任何它想做的事情。某些实现将 null 指针视为长度为 0 的字符串。有些则不然。std::string