当覆盖 << (流)运算符时,调试会进入 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<<
.
这个问题已经得到部分回答:解决方案是在我的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<<
.