是否使用c_str具有异常未定义的行为?

Gui*_*cot 3 c++ exception stack-unwinding undefined-behavior c++14

我看过几个类似的代码片段,如下所示:

struct MyExcept : std::exception {
    explicit MyExcept(const char* m) noexcept : message{m} {}

    const char* what() const noexcept override {
        return message;
    }

    const char* message;
};

void foo() {
    std::string error;

    error += "Some";
    error += " Error";

    throw MyExcept{error.c_str()};
}

int main() {
    try {
        foo();
    } catch (const MyExcept& e) {
        // Is this okay?
        std::cout << e.message << std::endl;
    }
}
Run Code Online (Sandbox Code Playgroud)

在注释后面的行中Is this okay?,我们读取了在foo函数中使用分配的c样式字符串std::string.由于字符串是通过堆栈展开来破坏的,这种未定义的行为是什么?


如果它确实是未定义的行为,如果我们main用这个替换函数怎么办?

int main() {
    foo();
}
Run Code Online (Sandbox Code Playgroud)

由于没有catch,编译器不会被强制解除堆栈,而是what()在控制台中输出结果并中止程序.那还是未定义的行为吗?

use*_*042 5

是的,这是未定义的行为.你正在使用一个悬垂的指针.

void foo() {
    std::string error;

    error += "Some";
    error += " Error";

    throw MyExcept{error.c_str()};
} // <<  error goes out of scope here and so does the pointer returned
  //     from c_str()
Run Code Online (Sandbox Code Playgroud)

由于没有catch,编译器不会被强制解除堆栈,而是what()在控制台中输出结果并中止程序.那还是未定义的行为吗?

由于默认实现将使用std::terminate并反过来调用,std::abort()这可能仍然是未定义的行为,因为大多数标准处理程序实现将尝试取消引用what().

您可以安装自己的处理程序以避免这种情况.

  • @GuillaumeRacicot就是不要这样做. (2认同)