使用空指针参数和不可能的后置条件构造标准异常 [英] Construct standard exceptions with null pointer argument and impossible postconditions

查看:72
本文介绍了使用空指针参数和不可能的后置条件构造标准异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下程序:

#include<stdexcept>
#include<iostream>

int main() {
    try {
        throw std::range_error(nullptr);
    } catch(const std::range_error&) {
        std::cout << "Caught!\n";
    }
}

带有libstdc ++的GCC和Clang调用std::terminate并通过消息中止程序

GCC and Clang with libstdc++ call std::terminate and abort the program with the message

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_S_construct null not valid

带有libc ++ segfault的Clang构造异常.

Clang with libc++ segfaults on construction of the exception.

请参见 godbolt .

编译器是否符合标准?标准 [diagnostics.range.error] 的相关部分(C ++ 17 N4659)确实说std::range_error具有const char*构造函数重载,应优先于const std::string&重载.本节也没有说明构造函数上的任何前提条件,而只说明了后置条件

Are the compilers behaving standard-conform? The relevant section of the standard [diagnostics.range.error] (C++17 N4659) does say that std::range_error has a const char* constructor overload which should be preferred over the const std::string& overload. The section also does not state any preconditions on the constructor and only states the postcondition

后置条件:strcmp(what(), what_­arg) == 0.

如果what_arg是空指针,则此后置条件始终具有未定义的行为,那么这是否意味着我的程序也具有未定义的行为并且两个编译器的行为一致?如果不是,应该如何阅读标准中如此不可能的后置条件?

This postcondition always has undefined behavior if what_arg is a null pointer, so does this mean that my program also has undefined behavior and that both compilers act conformant? If not, how should one read such impossible postconditions in the standard?

再三考虑一下,我认为这一定意味着程序的未定义行为,因为如果不这样做,那么也将允许(有效)不指向以空值结尾的字符串的指针,这显然是没有道理的.

On second thought, I think it must mean undefined behavior for my program, because if it didn't then (valid) pointers not pointing to null-terminated strings would also be allowed, which clearly makes no sense.

因此,假设这是正确的,我想将问题更多地集中在标准如何暗示这种未定义的行为上.是否由于后置条件的可能性而导致调用也具有未定义的行为,还是先决条件被简单地遗忘了?

So, assuming that is true, I would like to focus the question more on how the standard implies this undefined behavior. Does it follow from the impossibility of the postcondition that the call also has undefined behavior or was the precondition simply forgotten?

此问题的启发.. >

Inspired by this question.

推荐答案

来自文档:

由于不允许复制std :: range_error引发异常, 此消息通常在内部存储为单独分配的消息 引用计数的字符串.这也是为什么没有构造函数的原因 采取std :: string&& ;:无论如何都必须复制内容.

Because copying std::range_error is not permitted to throw exceptions, this message is typically stored internally as a separately-allocated reference-counted string. This is also why there is no constructor taking std::string&&: it would have to copy the content anyway.

这说明了为什么会出现段错误,API确实将其视为真实字符串. 通常,在cpp中,如果某些东西是可选的,则将有一个重载的构造函数/函数,它不需要任何不需要的内容.因此,将nullptr传递给未说明可选内容的函数将是未定义的行为.通常,API不会使用C字符串除外的指针.因此,恕我直言,可以安全地假设为期望const char *的函数传递nullptr将是未定义的行为.对于这些情况,较新的API可能更喜欢std::string_view.

This shows why you get segfault, the api does really treat it as a real string. In general in cpp if something was optional, there will be an overloaded constructor/function that does not take what it does not need. So passing nullptr for a function that does not document something to be optional is going to be undefined behavior. Usually API's don't take pointers with the exception for C strings. So IMHO it is safe to assume passing nullptr for a function that expects a const char *, is going to be undefined behavior. Newer APIs may prefer std::string_view for those cases.

更新:

通常,假设一个C ++ API带有一个接受NULL的指针,这是很公平的.但是,C字符串是一种特殊情况.在std::string_view之前,没有更好的方法可以有效地传递它们.通常,对于接受const char *的API,应该假定它必须是有效的C字符串.即指向以'\ 0'结尾的char序列的指针.

Usually it is fair to assume a C++ API taking a pointer to accept NULL. However C strings are a special case. Until std::string_view, there was no better way to pass them efficiently. In general for an API accepting const char *, assumption should be is that it has to be a valid C string. i.e a pointer to a sequence of chars that terminates with a '\0'.

range_error可以验证指针不是nullptr,但不能验证指针是否以'\ 0'结尾.因此最好不要进行任何验证.

range_error could validate that the pointer is not nullptr but it cannot validate if it terminates with a '\0'. So it better not do any validation.

我不知道标准中的确切措词,但是该前提条件可能是自动假定的.

I don't know the exact wording in the standard, but this pre-condition is probably assumed automatically.

这篇关于使用空指针参数和不可能的后置条件构造标准异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆