locked
how to compare two hash_map RRS feed

  • Question

  • hi,all I have two hash_map:

    hash_map<BSTR, string> hmStyles1;
    hash_map<BSTR, string> hmStyles2;
    

    each contains a few html styles that I stores style values in BSTRs, and style names in strings, e.g. a pair of values "italic", "fontStyle".

    now i want to compare these two hash_maps, and put unique value pairs into a third hash_map, i.e. remove the duplicated ones. how to do tht?

    cheers

    daiyue

    Tuesday, May 31, 2011 10:54 PM

Answers

  • the owner of the BSTR is something like:
     
    HRESULT IHTMLStyle::get_fontStyle(BSTR *p)
     
    and I also want to get the followings:
     
    HRESULT IHTMLStyle::get_fontWeight(BSTR *p)
    HRESULT IHTMLStyle::get_fontSize(VARIANT *p)
    HRESULT IHTMLStyle::get_fontFamily(BSTR *p)
    HRESULT IHTMLStyle::get_textDecoration(BSTR *p)
    HRESULT IHTMLStyle::get_color(VARIANT *p)
     
    and as you said the situation:
     
    1: fontStyle = italic
    2: fontStyle = Normal
     
    could happen, and I believe that each of the above style features, carries an unique value, that is why I chose values as keys in hash_map, instead of "fontStyle" and strings like that. when this conflict happens, I would like to add the second pair as a new one into a third hash_map. The third hash_map includes all the unique style features of the original two hash_maps.
    OK, maybe reversing the roles of key and value will work for you, though it seems wrong to me. However, I would still use
     
    hash_map<wstring, wstring>
     
    rather than using a BSTR as key, which will cause all kinds of problems.
     
    If you are using a map, as opposed to a multimap, then you do not need to worry about duplicates, because map (and hash_map) do not allow duplicate keys. Just insert both of your original maps into the third one. You can use the size() method on the new map to convince yourself that any duplicates have been eliminated.
     
    BTW, for small amounts of data, map is simpler than hash_map.
     

    David Wilkinson | Visual C++ MVP
    • Marked as answer by daiyueweng Wednesday, June 1, 2011 4:18 PM
    Wednesday, June 1, 2011 3:46 PM
  • There is no reason why you cannot mix 16 bit BSTRs and 8 bit strings in a hash_map if that is what you want.  You cannot put 8 bit bstrs in a has_map because BSTRs are 16 bit inherently.  However it is a bit odd to mix 16 bit and 8 bit strings.  Why not just use 16 bit strings all around?

    The concerns expressed in this thread are not inherent to hash_map, rather the storage of raw pointers in an STL-like container.

    I personally dislike putting raw pointers into any STL container, as you wind up with all sorts of ownership and lifetime questions.  get_fontStyle allocate a new BSTR that you must deallocate? (I don't know, having never used that interface)  If so you must manually remember to destroy all the BSTRs in the hash_map before the hash_map is destroyed.  Furthermore, since each call to get_fontStyle would return a different address, you would never ever find a match in your map.  If get_fontStyle simply copies its BSTR pointer into p, then you have to deal with the possibility that the IHTMLStyle element will be destroyed, taking the BSTR with it but you may still be storing a copy of the pointer in the hash_map

    The key issue here is that a BSTR is a pointer to heap memory that is subject to deletion or leaking, not an object that manages its resources.  Copy the BSTR into a wstring and all of that is taken care of for you.  In addition you get the semantics you want of string comparison for the map keys instead of pointer comparison.

     

    • Marked as answer by daiyueweng Wednesday, June 1, 2011 4:18 PM
    Wednesday, June 1, 2011 3:58 PM
  • btw, since I am using IHTMLStylePtr instead of IHTMLStyle, and I am accessing the IHTMLStyle::fontStyle property, which returns a _bstr_t, instead of a BSTR pointer. so i wonder is it better. and how to convert _bstr_t to wstring/string
    Just cast the bstr_t to LPCWSTR (which is const wchar_t*) and use it to initialize the wstring.
     
    bstr_t test(L"Hello world!");
    wstring str((LPCWSTR)test);
     

    David Wilkinson | Visual C++ MVP
    • Marked as answer by daiyueweng Wednesday, June 1, 2011 4:47 PM
    Wednesday, June 1, 2011 4:42 PM

All replies

  • You can check the hash_map::value_comp for compare the maps and write your logic for put unique value pairs into a third hash_map.
    Thanks and Regards Selvam http://www15.brinkster.com/selvamselvam/
    Wednesday, June 1, 2011 4:02 AM
  • hi,all I have two hash_map:
     
    hash_map<BSTR, string> hmStyles1;
    hash_map<BSTR, string> hmStyles2;
     
    each contains a few html styles that I stores style values in BSTRs, and style names in strings, e.g. a pair of values "italic", "fontStyle".
     
    now i want to compare these two hash_maps, and put unique value pairs into a third hash_map, i.e. remove the duplicated ones. how to do tht?
    According to your description, do you not want to be using
     
    hash_map<string, BSTR>
     
    ?
     
    Also, are you sure you want to mix strings like this? std::string is an 8-bit string, and BSTR is a 16-bit string. And who is the owner of the BSTR? If it were my choice I think I would use
     
    hash_map<wstring, wstring>
     
    As to your question, what is supposed to happen if the two original maps have conflicting information, say
     
    1: fontStyle = italic
    2: fontstyle = bold
     
    ?
     
    If this cannot happen, you can just insert both maps into the new map; a hash_map will not allow duplicate keys (names). If conflicts can happen, and you want to let the second map overrule the first, then insert the first map and then the second.
     

    David Wilkinson | Visual C++ MVP
    Wednesday, June 1, 2011 1:01 PM
  • You also have a secondary problem that any default comparisons would be comparing BSTR addresses instead of string contents.  Best choice, IMO would be to use wstring where you were using BSTRs.
    Wednesday, June 1, 2011 2:13 PM
  • According to your description, do you not want to be using
     
    hash_map<string, BSTR>
     
    ?
     
    Also, are you sure you want to mix strings like this? std::string is an 8-bit string, and BSTR is a 16-bit string. And who is the owner of the BSTR? If it were my choice I think I would use
     
    hash_map<wstring, wstring>
     
    As to your question, what is supposed to happen if the two original maps have conflicting information, say
     
    1: fontStyle = italic
    2: fontstyle = bold
     
    ?
     
    If this cannot happen, you can just insert both maps into the new map; a hash_map will not allow duplicate keys (names). If conflicts can happen, and you want to let the second map overrule the first, then insert the first map and then the second.
     

    David Wilkinson | Visual C++ MVP

    the owner of the BSTR is something like:

    HRESULT IHTMLStyle::get_fontStyle(BSTR *p)

    and I also want to get the followings:

    HRESULT IHTMLStyle::get_fontWeight(BSTR *p)
    HRESULT IHTMLStyle::get_fontSize(VARIANT *p)
    HRESULT IHTMLStyle::get_fontFamily(BSTR *p)
    HRESULT IHTMLStyle::get_textDecoration(BSTR *p)
    HRESULT IHTMLStyle::get_color(VARIANT *p)

    and as you said the situation:

    1: fontStyle = italic
    2: fontStyle = Normal

    could happen, and I believe that each of the above style features, carries an unique value, that is why I chose values as keys in hash_map, instead of "fontStyle" and strings like that. when this conflict happens, I would like to add the second pair as a new one into a third hash_map. The third hash_map includes all the unique style features of the original two hash_maps.

    If hash_map cannot do the job, what other choices do I have? and also, why I cant put 8bit bstrs and 16bit strings together in the hash_map?

    cheers

    daiyue

    Wednesday, June 1, 2011 3:32 PM
  • the owner of the BSTR is something like:
     
    HRESULT IHTMLStyle::get_fontStyle(BSTR *p)
     
    and I also want to get the followings:
     
    HRESULT IHTMLStyle::get_fontWeight(BSTR *p)
    HRESULT IHTMLStyle::get_fontSize(VARIANT *p)
    HRESULT IHTMLStyle::get_fontFamily(BSTR *p)
    HRESULT IHTMLStyle::get_textDecoration(BSTR *p)
    HRESULT IHTMLStyle::get_color(VARIANT *p)
     
    and as you said the situation:
     
    1: fontStyle = italic
    2: fontStyle = Normal
     
    could happen, and I believe that each of the above style features, carries an unique value, that is why I chose values as keys in hash_map, instead of "fontStyle" and strings like that. when this conflict happens, I would like to add the second pair as a new one into a third hash_map. The third hash_map includes all the unique style features of the original two hash_maps.
    OK, maybe reversing the roles of key and value will work for you, though it seems wrong to me. However, I would still use
     
    hash_map<wstring, wstring>
     
    rather than using a BSTR as key, which will cause all kinds of problems.
     
    If you are using a map, as opposed to a multimap, then you do not need to worry about duplicates, because map (and hash_map) do not allow duplicate keys. Just insert both of your original maps into the third one. You can use the size() method on the new map to convince yourself that any duplicates have been eliminated.
     
    BTW, for small amounts of data, map is simpler than hash_map.
     

    David Wilkinson | Visual C++ MVP
    • Marked as answer by daiyueweng Wednesday, June 1, 2011 4:18 PM
    Wednesday, June 1, 2011 3:46 PM
  • There is no reason why you cannot mix 16 bit BSTRs and 8 bit strings in a hash_map if that is what you want.  You cannot put 8 bit bstrs in a has_map because BSTRs are 16 bit inherently.  However it is a bit odd to mix 16 bit and 8 bit strings.  Why not just use 16 bit strings all around?

    The concerns expressed in this thread are not inherent to hash_map, rather the storage of raw pointers in an STL-like container.

    I personally dislike putting raw pointers into any STL container, as you wind up with all sorts of ownership and lifetime questions.  get_fontStyle allocate a new BSTR that you must deallocate? (I don't know, having never used that interface)  If so you must manually remember to destroy all the BSTRs in the hash_map before the hash_map is destroyed.  Furthermore, since each call to get_fontStyle would return a different address, you would never ever find a match in your map.  If get_fontStyle simply copies its BSTR pointer into p, then you have to deal with the possibility that the IHTMLStyle element will be destroyed, taking the BSTR with it but you may still be storing a copy of the pointer in the hash_map

    The key issue here is that a BSTR is a pointer to heap memory that is subject to deletion or leaking, not an object that manages its resources.  Copy the BSTR into a wstring and all of that is taken care of for you.  In addition you get the semantics you want of string comparison for the map keys instead of pointer comparison.

     

    • Marked as answer by daiyueweng Wednesday, June 1, 2011 4:18 PM
    Wednesday, June 1, 2011 3:58 PM
  • There is no reason why you cannot mix 16 bit BSTRs and 8 bit strings in a hash_map if that is what you want.  You cannot put 8 bit bstrs in a has_map because BSTRs are 16 bit inherently.  However it is a bit odd to mix 16 bit and 8 bit strings.  Why not just use 16 bit strings all around?

    The concerns expressed in this thread are not inherent to hash_map, rather the storage of raw pointers in an STL-like container.

    I personally dislike putting raw pointers into any STL container, as you wind up with all sorts of ownership and lifetime questions.  get_fontStyle allocate a new BSTR that you must deallocate? (I don't know, having never used that interface)  If so you must manually remember to destroy all the BSTRs in the hash_map before the hash_map is destroyed.  Furthermore, since each call to get_fontStyle would return a different address, you would never ever find a match in your map.  If get_fontStyle simply copies its BSTR pointer into p, then you have to deal with the possibility that the IHTMLStyle element will be destroyed, taking the BSTR with it but you may still be storing a copy of the pointer in the hash_map

    The key issue here is that a BSTR is a pointer to heap memory that is subject to deletion or leaking, not an object that manages its resources.  Copy the BSTR into a wstring and all of that is taken care of for you.  In addition you get the semantics you want of string comparison for the map keys instead of pointer comparison.

    HRESULT IHTMLStyle::get_fontStyle(BSTR *p)
    
    p
    
    Pointer to a variable of type BSTR that receives one of the values listed in Possible Values.

    that is all the doc tells me, so i dont know whether get_fontStyle allocate a new BSTR or not; and I will use <wstring, wstring> or <string, string> pairs instead of <BSTR, string> in the map.

    btw, since I am using IHTMLStylePtr instead of IHTMLStyle, and I am accessing the IHTMLStyle::fontStyle property, which returns a _bstr_t, instead of a BSTR pointer. so i wonder is it better. and how to convert _bstr_t to wstring/string 

    daiyue

    Wednesday, June 1, 2011 4:29 PM
  • btw, since I am using IHTMLStylePtr instead of IHTMLStyle, and I am accessing the IHTMLStyle::fontStyle property, which returns a _bstr_t, instead of a BSTR pointer. so i wonder is it better. and how to convert _bstr_t to wstring/string
    Just cast the bstr_t to LPCWSTR (which is const wchar_t*) and use it to initialize the wstring.
     
    bstr_t test(L"Hello world!");
    wstring str((LPCWSTR)test);
     

    David Wilkinson | Visual C++ MVP
    • Marked as answer by daiyueweng Wednesday, June 1, 2011 4:47 PM
    Wednesday, June 1, 2011 4:42 PM

  • Just cast the bstr_t to LPCWSTR (which is const wchar_t*) and use it to initialize the wstring.
     
    bstr_t test(L"Hello world!");
    wstring str((LPCWSTR)test);
     

    David Wilkinson | Visual C++ MVP

    can i do wstring wstr(text) instead?

    cheers

    daiyue

    Wednesday, June 1, 2011 5:21 PM
  • Just cast the bstr_t to LPCWSTR (which is const wchar_t*) and use it to initialize the wstring.
     
    bstr_t test(L"Hello world!");
    wstring str((LPCWSTR)test);
     

    David Wilkinson | Visual C++ MVP
    can i do wstring wstr(text) instead?
    Why don't you try it?
     

    David Wilkinson | Visual C++ MVP
    Wednesday, June 1, 2011 6:06 PM