std::map<int, std::string[2]> problems

Discussion in 'C++' started by =?ISO-8859-1?Q?Erik_Wikstr=F6m?=, Jun 13, 2005.

  1. First of all, forgive me if this is the wrong place to ask this question,
    if it's a stupid question (it's my second week with C++), or if this is
    answered some place else (I've searched but not found anything).

    Here's the problem, I have two sets of files, the name of a file contains a
    number which is unique for each set but it's possible (even probable) that
    two files in different sets have the same numbers. I want to store these
    file-names in such a way that I can retrieve them by their number. For this
    I thought I'd use a map with the number as the key an an array of strings
    to store the file-names, however I've run into trouble when trying to use
    this solution.

    When adding the file-names to the map I don't know if a filename from the
    other set already exists, but given examples at:
    http://www.fredosaurus.com/notes-cpp/stl-containers/map/pair.html
    http://www.fredosaurus.com/notes-cpp/stl-containers/map/map-ex-wordfreq.html
    it seams like entries not found are created and if they are found I can
    modify them.


    Here's code that displays my problem:

    #include <map>
    #include <string>
    #include <vector>

    using std::map;
    using std::string;
    using std::vector;

    class Files
    {
    public:
    void nextFile(string*, string*);
    void open(vector<string>*, int);

    private:
    int getNumber(string); // Gets the number from the filename

    map<int, string[2]> fileSets;
    map<int, string[2]>::iterator iter;
    };

    // Return the next pair of files
    // I've removed a bit of code to keep it short,
    // among other things checks for fileSets.end().
    void Files::nextFile(string* file1, string* file2)
    {
    iter++;
    // Return the pointers to the filenames
    file1 = &(iter->second[0]);
    file2 = &(iter->second[1]);
    }


    // Add files to the sets
    // files is a vector with the filenames to be added.
    // setNr is the number of the set the files should be
    // added to, can be 0 or 1.
    void Files::eek:pen(vector<string>* files, int setNr)
    {
    if(setNr < 2)
    {
    for(int i = 0; i < files->size(); i++)
    {
    // Add the file to the correct set
    int fileNumber = getNumber((*files));
    (fileSets[fileNumber])[setNr] = (*files);
    // This does not work ^^^^^^^
    }
    }

    // Set the iterator
    iter = fileSets.begin();
    }

    ------------------------------------------

    When compiling on gcc 3.3 I get the following:

    /usr/include/c++/3.3.4/bits/stl_map.h: In member function `_Tp& std::map<_Key,
    _Tp, _Compare, _Alloc>::eek:perator[](const _Key&) [with _Key = int, _Tp =
    std::string[2], _Compare = std::less<int>, _Alloc =
    std::allocator<std::pair<const int, std::string[2]> >]':
    Files.cpp:46: instantiated from here
    /usr/include/c++/3.3.4/bits/stl_map.h:319: error: ISO C++ forbids casting to an
    array type `std::string[2]'

    ------------------------------------------
    and I get similar results when using gcc 3.4. Obviously there's some problem
    with the array but I can't figure out what and would appreciate a nudge in the
    right direction, and since I'm still learning any other comment too.

    PS:
    It's not possible to get random access to a map if the key is not known
    but if I have an (bidirectional) iterator pointing at some element in the
    map, and know that the element I'm interested in is N elements from the one
    the iterator is currently pointing at can I jump to that element by adding
    N to the iterator, e.g. iter+=N ?

    --
    Erik Wikström
    =?ISO-8859-1?Q?Erik_Wikstr=F6m?=, Jun 13, 2005
    #1
    1. Advertising

  2. Erik Wikström wrote:
    > First of all, forgive me if this is the wrong place to ask this question,


    It's not. You're fine.

    > if it's a stupid question (it's my second week with C++), or if this is
    > answered some place else (I've searched but not found anything).


    It may have been answered already, but sometimes it's rather hard to find.

    > [...]
    >
    > map<int, string[2]> fileSets;


    You simply can't do that. Arrays cannot be the stored data in a standard
    container. If you need two strings there, either make a pair (std::pair)
    or make your own struct.

    > [...]


    V
    Victor Bazarov, Jun 13, 2005
    #2
    1. Advertising

  3. =?ISO-8859-1?Q?Erik_Wikstr=F6m?=

    Heinz Ozwirk Guest

    "Erik Wikström" <> schrieb im Newsbeitrag
    news:XOkre.27197$...
    > Here's the problem, I have two sets of files, the name of a file contains
    > a
    > number which is unique for each set but it's possible (even probable) that
    > two files in different sets have the same numbers. I want to store these
    > file-names in such a way that I can retrieve them by their number. For
    > this
    > I thought I'd use a map with the number as the key an an array of strings
    > to store the file-names, however I've run into trouble when trying to use
    > this solution.


    As Victor already explained, you cannot use a C style array as the value
    type of a standard container. But you could use an std:: vector instead.
    However, as you describe your problem, you have two sets of files, not one
    set of pairs of files. So I would suggest to use two instances of
    std::map<int, std::string>, one for each set of files.

    > PS:
    > It's not possible to get random access to a map if the key is not known
    > but if I have an (bidirectional) iterator pointing at some element in the
    > map, and know that the element I'm interested in is N elements from the
    > one
    > the iterator is currently pointing at can I jump to that element by adding
    > N to the iterator, e.g. iter+=N ?


    Have a look at std::advance.

    HTH
    Heinz
    Heinz Ozwirk, Jun 13, 2005
    #3
  4. Victor Bazarov wrote:
    > Erik Wikström wrote:
    > > map<int, string[2]> fileSets;

    > You simply can't do that. Arrays cannot be the stored data
    > in a standard container. If you need two strings there,
    > either make a pair (std::pair)


    But in the case in question, the array did not constitute
    the "stored data". The "stored data" elements in the map
    are actually of type std::pair<int, std::string[2]>.
    What's wrong with that?


    --
    Cheers,
    Robbie Hatley
    Tustin, CA, USA
    email: lonewolfintj at pacbell dot net
    web: home dot pacbell dot net slant earnur slant



    ----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
    http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
    ----= East and West-Coast Server Farms - Total Privacy via Encryption =----
    Robbie Hatley, Jun 14, 2005
    #4
  5. "Gernot Frisch" <> wrote in message
    news:...
    > > map<int, string[2]> fileSets;

    >
    > string[2] has no = operator and no < operator - that's the whole
    > problem.
    > -Gernot


    The comparison in the original post was being done on type int,
    which DOES have "=" and "<" operators. std::map contains elements
    of type std::pair<key_type, value_type>. Only the key_type
    needs to be "comparable", as i understand it.

    For example, the following program compiles fine:

    #include <iostream>
    #include <string>
    #include <map>
    #include <utility>
    using std::cout;
    using std::endl;
    using std::string;
    using std::map;
    using std::pair;
    using std::make_pair;
    int main(void)
    {
    string Splat[2] = {"apple", "peach"};
    map<int, string[2]> fileSets;
    fileSets.insert(make_pair<int, string[2]>(37, Splat));
    return 0;
    }

    However, when I try to run it, I get a general protection fault.
    What am I doing wrong? I don't think it has to do with the
    non-comparibility of std::string[2] , though. GPF usually
    means illegal memory usage somewhere. (Possibly a problem
    with the copy semantics of std::string[2]?)


    Puzzled,
    Robbie Hatley
    Tustin, CA, USA
    email: lonewolfintj at pacbell dot net
    web: home dot pacbell dot net slant earnur slant



    ----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
    http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
    ----= East and West-Coast Server Farms - Total Privacy via Encryption =----
    Robbie Hatley, Jun 14, 2005
    #5
  6. "Robbie Hatley" <lonewolfintj at pacbell dot net> schrieb im
    Newsbeitrag news:42aec9a5$...
    > "Gernot Frisch" <> wrote in message
    > news:...
    >> > map<int, string[2]> fileSets;

    >>
    >> string[2] has no = operator and no < operator - that's the whole
    >> problem.
    >> -Gernot

    >
    > The comparison in the original post was being done on type int,
    > which DOES have "=" and "<" operators. std::map contains elements
    > of type std::pair<key_type, value_type>. Only the key_type
    > needs to be "comparable", as i understand it.
    >
    > For example, the following program compiles fine:
    >
    > #include <iostream>
    > #include <string>
    > #include <map>
    > #include <utility>
    > using std::cout;
    > using std::endl;
    > using std::string;
    > using std::map;
    > using std::pair;
    > using std::make_pair;
    > int main(void)
    > {
    > string Splat[2] = {"apple", "peach"};
    > map<int, string[2]> fileSets;
    > fileSets.insert(make_pair<int, string[2]>(37, Splat));
    > return 0;
    > }
    >
    > However, when I try to run it, I get a general protection fault.
    > What am I doing wrong? I don't think it has to do with the
    > non-comparibility of std::string[2] , though. GPF usually
    > means illegal memory usage somewhere. (Possibly a problem
    > with the copy semantics of std::string[2]?)
    >


    The second argument must either have an = operator or an cctor - I'm
    not sure, I think it't the = op, which string[2] does not offer.
    Gernot Frisch, Jun 14, 2005
    #6
  7. Gernot Frisch wrote:

    > The second argument must either have an = operator or an cctor - I'm
    > not sure, I think it't the = op, which string[2] does not offer.


    For each STL container holds that the value type must be assignable and copy
    constructable (23.1.3).

    But why does this code compile?

    Mathias
    Mathias Waack, Jun 14, 2005
    #7
  8. =?ISO-8859-1?Q?Erik_Wikstr=F6m?=

    Dan Cernat Guest

    I suspect that string[2] decays to a pointer to its first element.

    Dan
    Dan Cernat, Jun 14, 2005
    #8
  9. Dan Cernat wrote:
    > I suspect that string[2] decays to a pointer to its first element.


    Huh? Decays? Where?

    Most likely it compiles in some situations because none of the member
    function of the class template 'map' are used that require copying or
    assigning of the value. As soon as you employ one of them, there will
    be an error.

    V
    Victor Bazarov, Jun 14, 2005
    #9
  10. =?ISO-8859-1?Q?Erik_Wikstr=F6m?=

    Dan Cernat Guest

    Well, actually, I tried the code on VC7.1 and it doesn't compile
    (cannot create the pair because it cannot find the appropriate copy
    constructor for the type string[2]).
    I was thinking that it compiles because, in the process of construction
    of the contained element of type string[2], it converts the array into
    a pointer to its first element and it copies the pointer, hence the GPF
    he gets.

    Your explanation doesn't explain the GPF he gets.

    Dan
    Dan Cernat, Jun 14, 2005
    #10
  11. Dan Cernat wrote:
    > [..]
    > Your explanation doesn't explain the GPF he gets.


    No, it doesn't. It wasn't meant to. The code is not supposed
    to compile. For all I know, he runs some other program that
    gives him the GPF while the code posted never actually makes it
    to the executable stage.

    If he needs the GPF explained, he has to go to the newsgroup for
    the particular compiler he uses (and that's not VC+ v6 or v7.1
    since both rightfully refuse to compile the code) and ask there.

    V
    Victor Bazarov, Jun 14, 2005
    #11
  12. =?ISO-8859-1?Q?Erik_Wikstr=F6m?=

    Ron Natalie Guest

    Victor Bazarov wrote:
    > Dan Cernat wrote:
    >
    >> [..]
    >> Your explanation doesn't explain the GPF he gets.

    >
    >
    > No, it doesn't. It wasn't meant to. The code is not supposed
    > to compile.

    Actually, it's undefined behavior. Speculating on whether it compiles
    or does something useful when it runs is just silly.
    Ron Natalie, Jun 14, 2005
    #12
  13. Victor Bazarov wrote:

    > No, it doesn't. It wasn't meant to. The code is not supposed
    > to compile. For all I know, he runs some other program that
    > gives him the GPF while the code posted never actually makes it
    > to the executable stage.


    The code compiles fine at least with gcc 3.3.5. And raises an exception
    during runtime.

    Mathias
    Mathias Waack, Jun 15, 2005
    #13
  14. > The code compiles fine at least with gcc 3.3.5. And raises an
    > exception
    > during runtime.


    How 'bout gcc 3.4?
    Gernot Frisch, Jun 15, 2005
    #14
  15. Regarding my test program that compiles but crashes:

    #include <iostream>
    #include <string>
    #include <map>
    #include <utility>
    using std::cout;
    using std::endl;
    using std::string;
    using std::map;
    using std::pair;
    using std::make_pair;
    int main(void)
    {
    string Splat[2] = {"apple", "peach"};
    map<int, string[2]> fileSets;
    fileSets.insert(make_pair<int, string[2]>(37, Splat));
    return 0;
    }

    The comments went:

    Gernot Frisch:
    > The second argument must either have an = operator
    > or an cctor - I'm not sure, I think it't the = op,
    > which string[2] does not offer.


    Mathias Waack:
    > For each STL container holds that the value type must be
    > assignable and copy constructable (23.1.3).
    > But why does this code compile?


    "Gernot Frisch":
    > The code compiles fine at least with gcc 3.3.5. And raises an
    > exception
    > during runtime.
    > How 'bout gcc 3.4?



    I'm using the djgpp port of Gnu gcc version 3.4.3
    in Windows 2000 Professional DOS console.

    I have all the warning flags turned on, too:
    -Wall -Wextra -pedantic etc etc etc

    But gcc gives no warnings or errors when compiling
    the above program.

    I can see now that y'all are right, the program is flawed to the
    core because the list elements can't be copied. I'm pretty sure
    gcc creates an implicit default copy constructor for the pairs,
    but the ctor is going to make ptrs that point to God knows where,
    hence the GPFs.

    I think the following is more like what the OP wanted, and this
    compiles and runs without error:

    #include <iostream>
    #include <string>
    #include <map>
    #include <vector>
    #include <utility>

    using std::cout;
    using std::endl;
    using std::string;
    using std::map;
    using std::vector;
    using std::pair;
    using std::make_pair;

    class Files
    {
    public:
    void nextFile(string*, string*);
    void open(vector<string>*, int);

    //private: // make public for test
    int getNumber(string); // Gets the number from the filename

    //map<int, string[2]> fileSets; // NO!!!

    map<int, pair<string,string> > fileSets; // YES!!!

    map<int, pair<string,string> >::iterator iter;
    };

    int main(void)
    {
    Files MyFiles;
    pair<string,string> Splat;

    Splat = make_pair<string,string>("apple", "peach");
    MyFiles.fileSets.insert(make_pair<int, pair<string,string> >(48, Splat));

    Splat = make_pair<string,string>("cucumber", "dill");
    MyFiles.fileSets.insert(make_pair<int, pair<string,string> >(23, Splat));

    cout
    << "Map element 23 first string = "
    << MyFiles.fileSets[23].first
    << endl;

    cout
    << "Map element 23 second string = "
    << MyFiles.fileSets[23].second
    << endl;

    cout
    << "Map element 48 first string = "
    << MyFiles.fileSets[48].first
    << endl;

    cout
    << "Map element 48 second string = "
    << MyFiles.fileSets[48].second
    << endl;

    return 0;
    }


    --
    Cheers,
    Robbie Hatley
    Tustin, CA, USA
    email: lonewolfintj at pacbell dot net
    web: home dot pacbell dot net slant earnur slant



    ----== Posted via Newsfeeds.Com - Unlimited-Uncensored-Secure Usenet News==----
    http://www.newsfeeds.com The #1 Newsgroup Service in the World! 120,000+ Newsgroups
    ----= East and West-Coast Server Farms - Total Privacy via Encryption =----
    Robbie Hatley, Jun 15, 2005
    #15
  16. =?ISO-8859-1?Q?Erik_Wikstr=F6m?=

    Ron Natalie Guest

    Mathias Waack wrote:

    > The code compiles fine at least with gcc 3.3.5. And raises an exception
    > during runtime.
    >
    > Mathias

    GCC has an extension that allows array assignment. Standard
    C++ arrays are crippled.
    Ron Natalie, Jun 15, 2005
    #16
  17. Ron Natalie wrote:

    > Mathias Waack wrote:
    >
    >> The code compiles fine at least with gcc 3.3.5. And raises an exception
    >> during runtime.
    >>
    >> Mathias

    > GCC has an extension that allows array assignment. Standard
    > C++ arrays are crippled.


    cat t2.cpp; g++ -Wall -c t2.cpp
    int main()
    {
    int s0[2];
    int s1[2] = s0;
    int s2[2];
    s2 = s0;
    }
    t2.cpp: In function `int main()':
    t2.cpp:4: error: invalid initializer
    t2.cpp:6: error: ISO C++ forbids assignment of arrays
    t2.cpp:4: warning: unused variable `int s1[2]'

    Mathias
    Mathias Waack, Jun 15, 2005
    #17
  18. On 2005-06-13 23:41, Heinz Ozwirk wrote:
    > "Erik Wikström" <> schrieb im Newsbeitrag
    > news:XOkre.27197$...
    >> Here's the problem, I have two sets of files, the name of a file contains
    >> a
    >> number which is unique for each set but it's possible (even probable) that
    >> two files in different sets have the same numbers. I want to store these
    >> file-names in such a way that I can retrieve them by their number. For
    >> this
    >> I thought I'd use a map with the number as the key an an array of strings
    >> to store the file-names, however I've run into trouble when trying to use
    >> this solution.

    >
    > As Victor already explained, you cannot use a C style array as the value
    > type of a standard container. But you could use an std:: vector instead.
    > However, as you describe your problem, you have two sets of files, not one
    > set of pairs of files. So I would suggest to use two instances of
    > std::map<int, std::string>, one for each set of files.
    >
    >> PS:
    >> It's not possible to get random access to a map if the key is not known
    >> but if I have an (bidirectional) iterator pointing at some element in the
    >> map, and know that the element I'm interested in is N elements from the
    >> one
    >> the iterator is currently pointing at can I jump to that element by adding
    >> N to the iterator, e.g. iter+=N ?

    >
    > Have a look at std::advance.


    Thank you all for your answers, I went with std::pair as Victor said and it
    works great.

    --
    Erik Wikström
    =?ISO-8859-1?Q?Erik_Wikstr=F6m?=, Jun 15, 2005
    #18
  19. =?ISO-8859-1?Q?Erik_Wikstr=F6m?=

    Stephen Howe Guest

    > But in the case in question, the array did not constitute
    > the "stored data". The "stored data" elements in the map
    > are actually of type std::pair<int, std::string[2]>.
    > What's wrong with that?


    The fact that the value element is an array : string[2]
    You cannot have an C-style array as key or value or both, regardless as to
    what the elements are.

    Stephen Howe
    Stephen Howe, Jun 16, 2005
    #19
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Peter Jansson
    Replies:
    5
    Views:
    6,263
    Ivan Vecerina
    Mar 17, 2005
  2. Schnoffos
    Replies:
    2
    Views:
    1,194
    Martien Verbruggen
    Jun 27, 2003
  3. Replies:
    1
    Views:
    404
    red floyd
    Dec 21, 2008
  4. Thomas J. Gritzan
    Replies:
    6
    Views:
    996
    James Kanze
    Dec 22, 2008
  5. James Kanze
    Replies:
    0
    Views:
    1,980
    James Kanze
    Dec 21, 2008
Loading...

Share This Page