1

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.

halfer
  • 19,824
  • 17
  • 99
  • 186
OneRaynyDay
  • 3,658
  • 2
  • 23
  • 56
  • If `print()` is being called then surely your overridden `operator<<` is called? Also, your `operator<<` should be declared `const`. – sjrowlinson Jul 05 '16 at 16:34
  • Looks like your class has a cast operator, which gets invoked to convert an `EscapeStr` to `char const*`. It's most likely that the your `operaro<<` function is not declared at the time you call it. – R Sahu Jul 05 '16 at 16:34
  • @ArchbishopOfBanterbury I would think so as well, but I put breakpoints on every line of that operator overload and it never stepped in. – OneRaynyDay Jul 05 '16 at 16:35
  • 1
    An MCVE should be complete and verifiable. We can't compile this for ourselves and see the error. And before the whole definition of `EscapeStr` gets added, it is likely that most of it does not affect this behaviour and can be removed (in the spirit of an MCVE being minimal). – chris Jul 05 '16 at 16:35
  • @RSahu It does not have a cast operator unfortunately. The only public function(in fact, the only function other than the ctor) is the print function. – OneRaynyDay Jul 05 '16 at 16:35
  • @chris my apologies, I'll include the implementation of the class and some extra code for MVCE. Thanks for the advice. I have added the impl of the class. It's just the stack overflow community is often very tl;dr and if I supply too much code noone would want to read it, so I often add too little information on accident. – OneRaynyDay Jul 05 '16 at 16:36
  • One wild guess: in which `namespace` did you put your override? – lorro Jul 05 '16 at 16:57
  • The whole point of a MCVE is that we can reproduce the error, because [I currently can't](https://ideone.com/K82m8U). Does the string get printed? Or is it just not going into `operator<<` when you debug? – Rakete1111 Jul 05 '16 at 17:01
  • @lorro it's the same place as my other `operator<<`. They're both inside a namespace called avro(Everything that uses the EscapeStr, including itself is in the namespace). @Rakete1111 It's not currently going into `operator<<` when I debug. The string that's supposed to be "escaped" shouldn't be printed correctly in fact. One second, I'll try fiddling on ideone. The behavior that your code is making might be UB. – OneRaynyDay Jul 05 '16 at 17:05
  • @Rakete1111 The fiddling is now in the post. There's no output from the stringstream that took the rdbuf() of my ostream. – OneRaynyDay Jul 05 '16 at 17:14
  • 1
    FWIW, your Ideone example [does call your `operator<<`](https://ideone.com/o0lgQS). – chris Jul 05 '16 at 19:12
  • You're right. It was Visual Studios lying to me, which threw me off. Thank you though! :) – OneRaynyDay Jul 05 '16 at 19:13

1 Answers1

3

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<<.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • Ah - you're right. I overlooked that mistake since I was so focused on trying to get the `operator<<` to work. I'll fix that and report back any results. Thanks for the catch! EDIT: Fixed, but I still can't see the operator<< going into my function. However, the output is as expected. Might this be an issue from visual studio? I'll leave this question open for a small while to encourage some discussion about the visual studio debugger, but I'll likely accept your answer since it fixed my output. – OneRaynyDay Jul 05 '16 at 17:20