如果没有使用 endl,重载的 ostream 运算符会导致分段错误。

7
class foo {
    public:
    friend ostream& operator << (ostream &os, const foo &f);
    foo(int n) : a(n) {}
    private:
    vector <int> a;
};

ostream& operator << (ostream &os, const foo &f) {
    for (int i = 0; i < f.a.size(); ++i)
        os << f.a[i] << " ";
    os << endl; // why is this line a must?
}

int main(void) {
    foo f(2);
    cout << f << endl;
    return 0;
}

在上面的代码中,如果删除标记行,将会出现段错误,有人能解释为什么吗?

1
为什么没有人关心检查代码中的问题?编译器应该警告您有这样的错误 - "...警告:在返回非void函数中没有返回语句[-Wreturn-type]"。请参见http://liveworkspace.org/code/2ygK20$1 } ^ - SChepurin
1个回答

19
ostream& operator << (ostream &os, const foo &f) {
    for (int i = 0; i < f.a.size(); ++i)
        os << f.a[i] << " ";
    os << endl; // why is this line a must?
}

这不是强制性的。导致段错误的原因是您没有返回os

ostream& operator << (ostream &os, const foo &f) {
    for (int i = 0; i < f.a.size(); ++i)
        os << f.a[i] << " ";
    return os; // Here
}

如果您不返回ostream,那么行为是未定义的。在这里,endl会刷新您的os。这就是为什么它似乎能够工作。

编辑:根据Bo Persson的解释,为什么它在这种情况下能够运行

os << endl;是另一个操作符调用,通过将它放置在“期望返回值”的位置(可能是寄存器)来实际返回os。当代码另一个级别返回到main时,对os的引用仍然存在。


4
这里没有隐式返回int。显然指定了返回类型为ostream&。所以如果没有return语句,函数结束后栈中右侧位置上的任何垃圾数据都会被返回。恰好在这里有了os<<endl,导致返回的是一个不会引起程序崩溃的值。 - BoBTFish
2
@honk 在 C++ 中没有隐式的 int。从非 void 函数中未返回任何内容只是未定义的行为,无论如何都是这样。 - Angew is no longer proud of SO
2
@Dave 你确实需要这样做。只是有些编译器可能不会告诉你你做错了什么。 - BoBTFish
3
从N3337(C++11之后的第一份草案)中的6.6.3节:「流程超出函数末尾等同于没有返回值的return; 在有返回值的函数中,这会导致未定义行为。」我猜编译器不认为这是一个错误的原因是有其他合法的方式退出函数(例如抛出异常)。 - BoBTFish
5
@Dave - os << endl; 是另一个操作符调用,它通过将 os 放置在“期望返回值的位置”(可能是一个寄存器)来实际返回 os。当代码返回到主函数的另一层时,对 os 的引用仍然存在。 - Bo Persson
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接