当覆盖 << (流)运算符时,调试会进入 std 的 << impl 吗?

When overriding the << (stream) operator, debug goes into std's << impl instead?

这个问题已经得到部分回答:解决方案是在我的class字段之一,特别是_escape,有UB。然而,仍然不知道为什么 Visual Studio 的堆栈跟踪不显示 operator<< 函数,调试器也找不到它——几乎就像有一个优化(我禁用了优化)来删除符号并合并它带打印功能。

我已经知道的

我看过 SO 上所有关于 << 运算符重载的热门帖子。我已经遵循了所有的基本语义。这不是任何热门帖子的重复问题。

要覆盖 << 运算符,需要定义一个通用格式的函数:

ostream& operator<<(ostream& os, const MyObject& dt)

我已经在我的程序中这样做了,

我正在为这个项目使用 Microsoft Visual Studio 2015,并使用调试器尝试进入 << 运算符函数。但是,它永远不会进入我定义如下的函数:

std::ostream& operator <<(std::ostream& os, const EscapeStr& t)
{
    t.print(os);
    return os;
}

其中 EscapeStr 是 class 我为 print 定义了以下函数定义:

void print(std::ostream& os) const { 
    for (int i = 0; i < _elem.length(); i++) {
        char c = _elem[i];
        if (_delim[c]) {
            for (int j = 0; j < _escLen; j++) {
                os << _escape[j];
            }
        }
        os << _elem[i];
    }
}

问题

我看到这里使用 VS 调试器调用了 print() 函数,但我无法观察到程序进入了我覆盖的 << 的范围,而是进入了 << 的标准定义,如下所示签名:

template<class _Traits> inline
    basic_ostream<char, _Traits>& operator<<(
        basic_ostream<char, _Traits>& _Ostr,
        const char *_Val);  // insert NTBS into char stream

这非常奇怪,因为目前只有 ostream 覆盖运算符可以访问我的 public 函数。 Visual Studio 是在撒谎吗?

我不明白发生了什么,因为我的其他重载之一确实有效,而且签名甚至不准确(没有 const 和引用):

/// ostream operator for indent
std::ostream& operator <<(std::ostream &os, indent x)
{
    static const std::string spaces("    ");
    while(x.d--) {
        os << spaces; 
    }
    return os;
}

因此,我的程序出现了一些 UB(阅读 std 库代码会让我发疯)。这是一个展示 UB 的想法:https://ideone.com/jxro5s。任何帮助将不胜感激。

关于 MVCE 和清晰度的额外信息

const static char _delims[] = { '\', '"' };
const static std::vector<char> delims(_delims, _delims + 2);

class EscapeStr {
    const static unsigned short MAX_CHAR = 256;

    std::string &_elem;
    bool _delim[MAX_CHAR];
    const char* _escape;
    int _escLen;
public:
    EscapeStr(std::string &elem,
        const std::vector<char> &delim = std::vector<char>(1, '"'),
        const std::string &escape = "\") :
        _elem(elem),
        _escape(escape.c_str()),
        _escLen(escape.size())
    {
        for (int i = 0; i < MAX_CHAR; i++) {
            _delim[i] = false;
        }
        for (int i = 0; i < delim.size(); i++) {
            _delim[delim[i]] = true;
        }
    }
    void print(std::ostream& os) const {
        for (int i = 0; i < _elem.length(); i++) {
            char c = _elem[i];
            if (_delim[c]) {
                for (int j = 0; j < _escLen; j++) {
                    os << _escape[j];
                }
            }
            os << _elem[i];
        }
    }
};

这是堆栈跟踪的图像 - 没有 << 运算符的符号。

编辑:预测未来 comments/posts 关于我不使用 std::quoted - 我试图使程序与低于 C++11 的版本兼容。

我认为要做的第一件事是在指向的临时字符串被销毁后修复从 _escape 读取的未定义行为。我认为最好的选择是将 const char* _escape; int _escLen; 替换为 std::string escape_;,然后您的 for 循环变为 os << escape_;。由于我们在这里谈论 UB,任何事情都可能发生,包括不调用您的自定义 operator<<.