User defined O/P stream buffer not printing output

Josuttis has given an example for creating a user-defined stream buffer, by inheriting from the streambuf class.
The custom buffer is then used to construct an ostream.

I have tried this, but it doesn't print O/P as expected.

The header file is shown below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/* The following code example is taken from the book
 * "The C++ Standard Library - A Tutorial and Reference, 2nd Edition"
 * by Nicolai M. Josuttis, Addison-Wesley, 2012
 *
 * (C) Copyright Nicolai M. Josuttis 2012.
 * Permission to copy, use, modify, sell and distribute this software
 * is granted provided this copyright notice appears in all copies.
 * This software is provided "as is" without express or implied
 * warranty, and with no claim as to its suitability for any purpose.
 */

#include <streambuf>
#include <locale>
#include <cstdio>

class outbuf : public std::streambuf
{
  protected:
    // central output function
    // - print characters in uppercase mode
    virtual int_type overflow (int_type c) {
        if (c != EOF) {
            // convert lowercase to uppercase
            c = std::toupper(c,getloc());

            // and write the character to the standard output
            if (std::putchar(c) == EOF) {
                return EOF;
            }
        }
        return c;
    }
};



The header is tested as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>             /// endl
#include <ostream>              /// ostream, flush

#include "outbuf1.hpp"

using namespace std;

int main()
{
    outbuf ob;           /// create special output buffer

    /// initialize output stream with that output buffer
    ostream out(&ob);

    out << "Hello, world!";
}



However, no O/P appears. What's the problem here?

Thanks.
Just a guess. I only recently noticed a problem with the implementation of some of the character functions such as isalpha() in the version of g++ I was using on Windows. My experience was to note that the British pound symbol '£' was incorrectly considered to be alphabetic. That was only the tip of the iceberg.

In the code here, try replacing the code to convert to uppercase,
23
24
            // convert lowercase to uppercase
            c = std::toupper(c,getloc());


Possibly this may work:
 
    c = std::toupper(c);

or failing that you might write your own (this is frowned upon - or at least making assumptions about the character encoding may be).

23
24
            // convert lowercase to uppercase
            c = (c >= 'a' && c <= 'z') ? c - ('a' - 'A') : c ;


But that's just a guess. It may be something else entirely.
Last edited on
Yes, your first solution works perfectly.

So the corrected header file is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <streambuf>
#include <cstdio>

class outbuf : public std::streambuf
{
  protected:
    // central output function
    // - print characters in uppercase mode
    virtual int_type overflow (int_type c)
    {
        if (c != EOF) {
            // convert lowercase to uppercase
            c = std::toupper(c);

            // and write the character to the standard output
            if (std::putchar(c) == EOF) {
                return EOF;
            }
        }
        return c;
    }
};


Thanks.
The problem in the code in the book is that in virtual int_type overflow (int_type c),
int_type is a type alias for int. std::toupper(c,getloc()); throws (in the libstdc++ implementation) because the default locale does not have the facet std::ctype<int>.

Note: libc++ spits out a compile-time error: implicit instantiation of undefined template 'std::__1::ctype<int>'
The Microsoft library works as expected by Josuttis; it apparently does have the facet std::ctype<int>

The problem with the modified code having a hard-coded std::toupper(c); would become apparent if we change the locale associated with the stream buffer with a call to pubimbue

This would be the right fix, it would work in a sane manner on all conforming implementations:

1
2
3
4
5
6
7
8
9
class outbuf : public std::streambuf
{
  protected: virtual int_type overflow (int_type c) {

            using ctype = std::ctype<char> ;

            return c != EOF ? std::putchar( std::use_facet<ctype>( getloc() ).toupper(c) ) : c ;
    }
};
Topic archived. No new replies allowed.