CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 11 of 11
  1. #1
    Join Date
    Jun 2000
    Location
    austin
    Posts
    101

    user defined types and std::map

    hello,
    i want to make a map keyed on strings represented by char* (i.e. c strings). how would i do this?

    it seems that if i declare map<char*, mytype>, then the keys would be the actual pointer and not the strings the pointers point to.

    example: i want this to work:
    const char* str1 = "test";
    const char* str2 = "test";
    map<char*, mytype*> m;
    m[str1] = my_data;
    assert(m.find(str2) != m.end());

    thank you,
    -- christopher

  2. #2
    Join Date
    May 2000
    Location
    Phoenix, AZ [USA]
    Posts
    1,347
    Check out the documentation for map.
    Use the third template argument to specify the comparison
    criterion.

    --Paul

  3. #3
    Join Date
    Feb 2002
    Posts
    5,757
    In terms of comparison, the default algorithm in the STL map container will compare points, not string. One solution is std::bind and a functor.

    Kuphryn

  4. #4
    Join Date
    Apr 2003
    Posts
    4
    Try

    std::map< std::string, your_type> coll;
    // works - implicit conversion
    coll[ "test"] = val;

    //etc.

    Best,
    John

  5. #5
    Join Date
    Apr 1999
    Posts
    27,449

    Re: user defined types and std::map

    Originally posted by clockworks
    hello,
    i want to make a map keyed on strings represented by char* (i.e. c strings). how would i do this?

    it seems that if i declare map<char*, mytype>, then the keys would be the actual pointer and not the strings the pointers point to.
    Why not use std::string instead of char*?
    Code:
    #include <string>
    //...
    std::string str1 = "test";
    std::string str2 = "test";
    map<std::string, mytype> m;
    m[str1] = my_data;
    assert(m.find(str2) != m.end());
    //...
    Regards,

    Paul McKenzie

  6. #6
    Join Date
    Aug 2002
    Location
    Madrid
    Posts
    4,588

    Re: Re: user defined types and std::map

    Originally posted by Paul McKenzie
    Why not use std::string instead of char*?
    Paul McKenzie
    I definitely agree with Paul on this one. Unless you are very very careful, using char *'s as index into a map will invariably lead to memory leaks. Use std:string, it's much safer and much easier to handle. There is practically no performance penalty either.

    For an example of the problems see this code:
    Code:
    // bad code !
    std::map<char *, int, StringComp> m;
    char *sz;
    
    sz = new char&#091;2&#093;;
    sz&#091;0&#093; = '0';
    sz&#091;1&#093; = 0;
    m&#091;sz&#093; = 25;
    // This char * now belongs to the map, 
    // so you should not free it until you free the item in the map
    
    sz = new char&#091;2&#093;;
    sz&#091;0&#093; = '0';
    sz&#091;1&#093; = 0;
    m&#091;sz&#093; = 10;
    // since "0" was already a key, it is not put into the map again
    // now you DO have to delete &#091;&#093; it.
    Simply awful
    Get this small utility to do basic syntax highlighting in vBulletin forums (like Codeguru) easily.
    Supports C++ and VB out of the box, but can be configured for other languages.

  7. #7
    Join Date
    Jun 2000
    Location
    austin
    Posts
    101
    std::string will not work for what i want. i'm writing a huffman encoder and i have a map of frequencies per "chunk". a chunk could be 1, 2, 3, or n bytes.

    so lets say i want to count the frequencies of 2 byte chunks of a text file. thus i want a map<char*, int> to do something like the following psudocode:
    char chunk[2];
    while (!eof) {
    read_chunk(chunk, file);
    freq_map[chunk] += 1;
    }

    obviously that won't work: no matter how interation of the loop, and diversity of the file, the map will be of size one at the end.

    i tried doing something like this:
    struct comp {
    bool operator()(const char* s1, const char* s2) {
    return memcmp(s1, s2, chunk_size) < 0;
    }
    };
    map<char*, int, comp> freq_map;

    but it doesn't solve the problem at all.

    thanks for the help,
    -- christopher

  8. #8
    Join Date
    Apr 1999
    Posts
    27,449
    Originally posted by clockworks
    std::string will not work for what i want. i'm writing a huffman encoder and i have a map of frequencies per "chunk". a chunk could be 1, 2, 3, or n bytes.
    std::string can be 1, 2, 3, or n bytes. So far your reasoning doesn't eliminate std::string
    so lets say i want to count the frequencies of 2 byte chunks of a text file. thus i want a map<char*, int> to do something like the following psudocode:
    char chunk[2];
    while (!eof) {
    read_chunk(chunk, file);
    freq_map[chunk] += 1;
    }
    This particular "chunk" is a sequence of some characters, correct? Does this same sequence keep changing but the pointer to it stay the same? Unless this is the reason for using pointers, there is nothing in the pseudo-code you posted that makes std::string unusable. As a matter of fact, the very first line (char chunk[2]) is a dead giveaway that std::string can be used.

    Regards,

    Paul McKenzie

  9. #9
    Join Date
    Jun 2000
    Location
    austin
    Posts
    101
    paul,
    excuse me, i'm a bit inebriated, but whats with the hints? no hints, just tell me how to do it...=)
    what if my chunk is 4 bytes:
    first byte: 0
    second: 0
    thrid: 0
    fourth: 10

    its my understanding that std::strings represent ascii strings. hence a 4 byte std::string can't start with 0 because that would be the empty string or something.

    let me try to be more clear. my chunk is:
    00000000 00000000 00000000 00001000.

    how would i store that in an std::string? and write it to a file using fwrite()?

    they don't teach stl in school, just algorithms, so i'm asking for explicit instructions on how to do this.

    i actually remedied (sp?) the problem. i made a class called chunk_t that overloads the == operator, the < operator, the = operator, and a bunch of constructors, etc. it was a pain in the ***, but it worked. my huffman encoder compressed an 800k file to 300k (using 2-3 byte chunks), but i don't like having to introduce a new class like this.

    anyways, thanks for the tips,
    -- christopher

  10. #10
    Join Date
    Apr 1999
    Posts
    27,449
    Originally posted by clockworks
    paul,
    excuse me, i'm a bit inebriated, but whats with the hints? no hints, just tell me how to do it...=)
    what if my chunk is 4 bytes:
    first byte: 0
    second: 0
    thrid: 0
    fourth: 10

    its my understanding that std::strings represent ascii strings. hence a 4 byte std::string can't start with 0 because that would be the empty string or something.
    OK clockworks, stop right there

    std::string does not necessarily wrap a null terminated string (if this was the reason for the apprehension in using it). Any sequence of bytes can be stored in a std::string, with the length of the string governed by the "length()" member function, not where a NULL may be located.

    If you take a look at the std::string constructor, one of the constructors is:

    std::string(const char *, size_type len);

    You also have the assign() member function to add a series of characters to the std::string. std::string is much more than what you may think it is.

    For your NULL example,
    Code:
    #include <string>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
        char chunk[] = { 0, 0, 0, 16 };
        std::string s;
        s.assign(chunk, 4);
        //OR
        std::string s2(chunk, 4);
        cout << "s has " << s.length() << " bytes "<< endl;
        cout << "s2 has " << s2.length() << " bytes "<< endl;
        cout << endl;
        for (int i = 0; i < s.length(); ++i)
            cout << (int)s[i] << endl;
        cout << endl;
        for (i = 0; i < s2.length(); ++i)
            cout << (int)s2[i] << endl;
    }
    
    Output:
    s has 4 bytes
    s2 has 4 bytes
    
    0
    0
    0
    16
    
    0
    0
    0
    16
    let me try to be more clear. my chunk is:
    00000000 00000000 00000000 00001000.

    how would i store that in an std::string? and write it to a file using fwrite()?
    Is this already in "char" form and not just a binary number? If it is already in char form, the above example answers your question.
    Code:
    char YourChunkString[32];
    // Assume YourChunkString has 32 characters.
    std::string sChunk(YourChunkString, 32);
    //...
    fwrite( sChunk.data(), 1, sChunk.length(), YourFile);
    If it isn't in char form, you have to convert it to binary. There is a C++ bitset class that helps you out that does the conversion, and you can save the conversion back to a std::string.
    Code:
    #include <bitset>
    unsigned long YourChunkNum = 1839343L;
    //...
    std::bitset<32> b32( YourChunkNum );
    std::string sChunk = b32.to_string();
    they don't teach stl in school, just algorithms, so i'm asking for explicit instructions on how to do this.
    Just come here for solutions
    i actually remedied (sp?) the problem. i made a class called chunk_t that overloads the == operator, the < operator, the = operator, and a bunch of constructors, etc. it was a pain in the ***, but it worked. my huffman encoder compressed an 800k file to 300k (using 2-3 byte chunks), but i don't like having to introduce a new class like this.
    Your code should be much neater once you use the std::string. Also, my suggestion is to get the book "The C++ Standard Library" by Nicolai Josuttis. It explains, in great depth, std::string and its capabilities.

    Regards,

    Paul McKenzie

  11. #11
    Join Date
    Jun 2000
    Location
    austin
    Posts
    101
    wow cool, thanks for the post...=) i'm gunna clean up the code right now to use std::string! and i'm definantly gunna check out that book your recommended.

    thank you,
    -- christopher

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured