#include <iostream>
#include <string>

using namespace std;

template<class T> class Sample {
private:
 T val;
public:
 Sample(T InitialVal=T()) : val(InitialVal)
 {
    // do nothing
 }
 ~Sample()
 {
    // do nothing
 }
 void PrintVal(void)
 {
     try {
    cout << "[" << val << "]" << endl;
     } catch(...) {
        cout << "exception thrown" << endl;
     }
 }
};

int main() {
    // your code goes here
    Sample<int> ints(20), intd;
    Sample<char *> chars(const_cast<char*>("Neelakantan")), charsd;
    Sample<string> s, ss("neel");

    ints.PrintVal();
    intd.PrintVal();

    chars.PrintVal();
    charsd.PrintVal(); // <<- Culprit line. Commenting out this line works as expected.

    s.PrintVal();
    ss.PrintVal();

    return 0;
}


当我运行上面的代码时,我得到以下输出:

sh-4.4$ g++ -o main *.cpp
sh-4.4$ main
[20]
[0]
[Neelakantan]
[sh-4.4$


当我注释掉“ charsd.PrintVal();”行时,得到以下输出:

[sh-4.4$ g++ -o main *.cpp
sh-4.4$ main
[20]
[0]
[Neelakantan]
[]
[neel]
sh-4.4$


Sample 类型的模板实例的'charsd'对象有什么问题?没有异常被抛出。

编译器版本:

sh-4.4$ g++ --version
g++ (GCC) 7.2.1 20170915 (Red Hat 7.2.1-2)
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

sh-4.4$

最佳答案

[根据新的信息/知识修改后的答案。另请参阅乔纳森·韦克利(Jonathan Wakeley)的答案(我在看到之前对此进行了更新),他是gcc / libstdc ++的撰稿人,并且选择了我提交的错误报告。非常感谢他为我做出直率而真诚的道歉,因为我做出了荒谬的假设,即ostream始终会像我之前描述的那样表现。

实际上,在故障点,您实际上正在做的是:

std::cout << (const char *) nullptr << std::endl;


大多数人期望得到的结果(尽管严格来说,您在这里所做的行为是不确定的)将是SEGFAULT。

但是,其中包含libstdc++,使用的ostream的实现的gcc有所不同。它在流上设置badbit,并且仅当您启用了badbit异常(默认情况下处于禁用状态)时,它(也会)引发异常。感谢Jonathan Wakeley在我提交有关此问题的错误报告时向我指出这一点,当我发布此答案的第一个版本时,我对此一无所知(显然也没有其他人向此主题发布)。

但是您的代码没有启用所述异常,因此所有发生的事情是badbit被设置为cout,并且随后所有后续写入均以静默方式失败。以前,我误解了这一点,因为传入nullptr时程序正在悄悄退出,但是我错了,并且我向开发人员表示歉意,因为他们做出了这种不必要的假设。评论中有更多关于此的内容。

因此,要在发生这种情况时引发异常,必须在流上启用badbit异常,您可以这样操作:

std::cout.exceptions (std::ostream::badbit | std::ios::failbit);


然后,您将获得希望的异常。就我个人而言,我不太喜欢这种行为,我更喜欢SEGFAULT(实际上,使用clang you do),但Jonathan告诉我,自2002年以来就是这样,开发人员有充分的理由不这样做立即更改。

有一个新的live demo显示了gcc的行为,并添加了以上一行,现在的输出为:

[20]
[0]
[Neelakantan]
terminate called after throwing an instance of 'std::__ios_failure'
  what():  basic_ios::clear: iostream error
[
Aborted


因此,请注意,陷入混乱的陷阱在于在那里等待,“为什么我的日志记录语句没有突然出现?”或类似的东西。

10-06 05:14