Search code examples
c++c++11dictionarycharacterlocale

Trouble getting character classification information from map


I have a program that maps the ctype identification of a character to a textual representation. I use a std::map to map a value of the mask (ctype_base::mask) to a string that represents the type of character in a string. The trouble I'm having is that when I attempt to print out the value, nothing gets printed to output. Why is this?

#include <iostream>
#include <map>
#include <vector>

class mask_attribute
{
private:
    typedef std::ctype_base base_type;
public:
    mask_attribute()
    {
        mask_names[base_type::space] = "space";
        mask_names[base_type::alpha] = "alpha";
        mask_names[base_type::digit] = "digit";
    }

    std::string get_mask_name(base_type::mask mask) const
    {
        std::string result = (*mask_names.find(mask)).second;
        return result;
    }
private:
    std::map<base_type::mask, std::string> mask_names;
};

int main()
{
    std::string a = "abc123";
    std::vector<std::ctype_base::mask> v(a.size());

    auto& f = std::use_facet<std::ctype<char>>(std::locale());
    f.is(&a[0], &a[0] + a.size(), &v[0]);

    for (unsigned i = 0; i < v.size(); ++i)
        std::cout << mask_attribute().get_mask_name(v[i]) << std::endl;
}

The output I expected was:

alpha
alpha
alpha
digit
digit
digit

but instead nothing is printed. What did I do wrong here and how do I fix it?


Solution

  • Print out v[i] as integer in hex, that might prove illuminating.

    You expect ctype::is to produce exactly one bit for each character. That is not what normally happens. For example, for 'a' you are likely to see alpha | lower | print. You don't have an entry for this in mask_names, so find returns mask_names.end(), which you promptly dereference, whereupon your program exhibits undefined behavior.