OneRaynyDay OneRaynyDay - 3 months ago 11
C++ Question

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

This question has been partially answered: the solution is that in one of my class's fields, specifically _escape, has UB. However, it is still unknown why Visual Studio's stack trace does not display the operator<< function nor does the debugger find it - almost as if there was an optimization(I disabled optimizations) to remove the symbol and merge it with the print function.

What I already know



I have seen all the popular posts on SO about << operator overload. I have followed all the basic semantics. This isn't a duplicate question of any of the popular posts.

To override the << operator, one needs to define a function with the general format of:

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


I have done so in my program,

I'm using Microsoft Visual Studio 2015 for this project, and using the debugger to try to step into the << operator function. However, it never gets inside of the function that I defined as follows:

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


where EscapeStr is a class I defined with the following function definition for
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];
}
}


The problem



I see the print() function being called here using the VS debugger, but I cannot observe the program entering the scope of my overridden <<, but rather it's going into the std definition of <<, with the following signature:

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


This is extremely weird, because only the ostream override operator has access to my public function currently. Is Visual Studio just lying?

I don't understand what's going on, as one of my other overloads do work, and the signature isn't even exact(without the const and reference):

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


As a result, my program is exhibiting some UB(reading the std library code would drive me insane). Here's an ideone to show the UB: https://ideone.com/jxro5s . Any help would be greatly appreciated.

Extra information for MVCE and clarity



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];
}
}
};


Here is an image of the stack trace - no sign of the << operator.
enter image description here

EDIT: To predict future comments/posts about me not using std::quoted - I'm trying to make the program compatible with versions less than C++11.

Answer

I think the first thing to do is fix the undefined behavior reading from _escape after the temporary string to which is points has been destroyed. The best option in my mind is to replace const char* _escape; int _escLen; with std::string escape_; and then your for loop becomes os << escape_;. Since we're talking about UB here, anything could happen including not calling your custom operator<<.

Comments