简体   繁体   中英

Issue with std::map having an std::map value

I want to create an std::map that maps QStrings onto another std::map. However, when I try to do this, it insteads seems to map them onto an std::_Tree.

The code that does this is here

// *** Meta Data ****
quint8 numMetaDataItems = getBufferUint<quint8>(&frameData[numMetaDataOffset]);
size_t metaDataItemOffset = numMetaDataOffset + sizeof(numMetaDataItems);
std::map<int, QString> tempMap;

for (int i = 0; i < numMetaDataItems; i++)
{
    int metadataId = getBufferUint<quint8>(&frameData[metaDataItemOffset]);
    QString metadata = QString::fromUtf8((const char*) &frameData[metaDataItemOffset + 1]) ;
    //tempMap.insert(std::pair<int, QString>(metadataId, metadata));
    metaDataModel->metaDataMap[fileName][metadataId] = metadata;
    metaDataItemOffset += headerLength - metaDataItemOffset;
}

When I use the debugger, the key for the map is correct but where the value should be another map, it instead says class std::_Tree<>. Can anyone explain why this is?

EDIT:

So I've realised that the problem may have nothing to do with the map. I try to access the map here:

QList<QString> strings;
for(std::map<int, QString>::iterator it = metaDataMap[frameID].begin(); it != metaDataMap[frameID].end(); it++)
{
    QString tempString = idMap[it->first] + ": " + it->second;
    strings.append(tempString);
}

But since there is only one item in the map it appears that .begin() and .end() are the same, and the code in the for loop is never run. Does that sound like it might be what's happening?

As this 'doc' states,

Maps are usually implemented as red-black trees.

This means, that in your compiler std::map<> is essentially a typedefed _Tree<> class, so there is nothing wrong about it.

When I use the debugger, the key for the map is correct but where the value should be another map, it instead says class std::_Tree<>. Can anyone explain why this is?

This hints at how your compiler implements std::map .

It looks like it's Visual C++. If you look at the header file on your machine (it should be something like C:\\Program Files (x86)\\Microsoft Visual Studio 12.0\\VC\\include\\map ), then you will probably see that std::map publicly derives from _Tree . There's nothing magic about it; it's just plain simple public derivation.

Now, the name _Tree already suggests that it is an implementation detail. A name like this (underscore + capital letter) would not be allowed in your own code, but the compiler itself can use it freely in its own header files. That's because as far as the C++ language is concerned, standard-library header files do not exist. You could perfectly write a conforming C++ compiler without any header files, where user code like #include <map> would be interpreted without reading any files. It's just for simplicity and practical reasons that all C++ compilers I'm aware of (and probably all that have ever existed) ship with header files .

The point is that the compiler's own header files may contain everything, including non-C++ code, proprietary constructs and other weird stuff which clients do not need to be aware of, but which the compiler needs in order to implement the C++ standard library.

_Tree is such a thing. Looking into a standard header file or using the debugger exposes you to it.


All of this is perfectly fine, as long as you don't try to fiddle with it in your own code. For example, take the following evil piece of code:

#include <map>

int main()
{
    // Just for demonstration purposes!
    // Do not EVER try this in production code!

    using namespace std;
    _Tree<_Tmap_traits<int,
        int,
        less<int>,
        allocator<int>,
        false>
    > m{ less<int>(), allocator<int>() };
}

It will very likely compile and work fine with MSVC but make your program non-portable and possibly even non-compatible with future or past versions of the same compiler, because you have used compiler-internal components in your own code.

In short: Your own code must be unaware of the fact that _Tree exists.

As you mentioned in your comments, the question is how to access from an std::map see my examples below:

#include<map>
#include<string>
#include<iostream>

int main()
{
    std::map<int,int> key = { {1,2}};
    std::map< std::map<int,int>,std::string> myMap;
    myMap[key]="hello";
    std::string val=  myMap[key];
    std::cout<<val;

}

EDIT

    std::map<int,int> key = { {1,2}};
    std::map< std::string, std::map<int,int>> myMap;
    myMap["hello"]=key;
    auto val=  myMap["hello"];
    for( const auto & p: val)
    std::cout<<p.first<<" "<<p.second;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM