CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 12 of 12
  1. #1
    Join Date
    May 2002
    Posts
    1,798

    Help needed with C++ class

    I wrote a little C++ class to implement the parsing of text into matrices. I works pretty well except that I cant seem to access the string vector that holds the numeric data as strings. It doesnt make sense to me because I can demonstrate that in at least one function of the class, the string vector is properly initialized. But when I try to acces it in another class function (the retrieval function), the vector has size = 0.

    Heres some pseudo-code to further explain my dilemma:

    Code:
    // lex.h
    
    #include <string>
    #include <vector>
    using namespace std;
    
    class CLex
    {
    public: 
     CLex(){ m_vs.resize(0);}
     virtual ~CLex(){}
    private:
     vector<string> m_vs;
     //...
    public:
     void parse(string s) 
     { // ... 
        m_vs.push_back("numeric string..."); 
     }
     vector<string> get_svec() { return m_vs; }
    
    };
    The problem here is that the member vector, m_vs gets properly initialized in the CLex:arse function, but when I try to use CLex::get_svec() to access the data, it comes up empty. Checking the value(s) of m_vs in the function get_svec, m_vs is empty. So what happened to it?

    Code:
    #include "lex.h"
    
    int main()
    {
        string s;
        vector<string> vs;
        CLex lx;
    
        s = "1 2 3\r\n4 5 6\r\n";
        lx.parse(s);
        vs = lx.get_svec() ;
        cout << vs[0] << endl;
    
    }
    The class member vector, m_vs, will have values of "1", "2", "3", "4", "5", "6" within the CLex:arse() function, but will be empty (have zero size) in the CLex::get_svec() function.

    Can anyone show me what I am doing wrong here? I'm sure it's something fairly simple and stupid as usual.

    Thanks.

    Mike
    Last edited by Mike Pliam; December 12th, 2003 at 02:00 PM.
    mpliam

  2. #2
    Join Date
    Sep 2003
    Location
    Forever Gone... For Now...
    Posts
    1,515
    I just looked briefly at the code, but perhaps you don't mean to return a copy of the vector:
    Code:
    vector<string> get_svec() { return m_vs; }
    but rather a reference?
    Code:
    vector<string>& get_svec() { return m_vs; }
    ?
    Thought for the day/week/month/year:
    Windows System Error 4006:
    Replication with a nonconfigured partner is not allowed.

  3. #3
    Join Date
    May 2002
    Posts
    1,798
    vic,

    Problem is that the vector is already size = 0 in that function, that is, within the class. How you return it is interesting but doesnt solve the problem.

    Mike
    mpliam

  4. #4
    Join Date
    Sep 2003
    Location
    Forever Gone... For Now...
    Posts
    1,515
    Originally posted by Mike Pliam
    vic,

    Problem is that the vector is already size = 0 in that function, that is, within the class. How you return it is interesting but doesnt solve the problem.

    Mike
    My thought was that you may have been getting back a copy of the vector and were changing the copy, and were watching the size of m_vs. Again, I didn't look at the code too closely. I prolly shouldn't have posted in the first place...
    Thought for the day/week/month/year:
    Windows System Error 4006:
    Replication with a nonconfigured partner is not allowed.

  5. #5
    Join Date
    Sep 2003
    Location
    Forever Gone... For Now...
    Posts
    1,515
    Mike, if I run the following program:
    Code:
    #include <string>
    #include <iostream>
    #include <vector>
    using namespace std;
    
    class CLex
    {
    public: 
     CLex(){ m_vs.resize(0);}
     virtual ~CLex(){}
    //private:
     vector<string> m_vs;
     //...
    public:
     void parse(string s) 
     { // ... 
        m_vs.push_back("numeric string..."); 
     }
     vector<string> get_svec() { return m_vs; }
    
    };
    
    
    int main()
    {
        string s;
        vector<string> vs;
        CLex lx;
    
        s = "1 2 3\r\n4 5 6\r\n";
        lx.parse(s);
        vs = lx.get_svec() ;
        cout << vs[0] << endl;
        cout << lx.m_vs[0] << endl;
    }
    in MSVC++ 6.0, I get the following results:
    Code:
    numeric string...
    numeric string...
    All I did is add the last cout to main, and made m_vs public (and included iostream).
    Is this not what you get? Or what you expect?
    Thought for the day/week/month/year:
    Windows System Error 4006:
    Replication with a nonconfigured partner is not allowed.

  6. #6
    Join Date
    Jun 2001
    Location
    Michigan
    Posts
    2,222
    I also ran a test and got the same results as vicodin, "Numeric String..." showed up while debugging the class and in the output. In case you're interested...

  7. #7
    Join Date
    May 1999
    Location
    Southern California
    Posts
    12,266
    Put a breakpoint near the end of "parse"; somewhere after the parsing has been done. Then debug the program and verify that m_vs has the strings as expected. Then single-step until parse returns; as you do, watch m_vs to ensure it continues to have the expected values. When you reach the "main" function following execution of parse, verify that lx.m_vs still has the expected values. Single-step into "get_svec" to see what it is returning. After get_svec returns, check to see what "vs" contains.

    Problems such as this often are the result of overlooking something. You are probably assuming that something is happening that is not happening or vice versa. To solve problems such as this, it helps to be methodical and not guess. Use procedures such as the above to verify assumptions.

    The problem probably exists in code we don't see.

  8. #8
    Join Date
    May 2002
    Posts
    1,798
    Sorry, Folks. Sam is right on. I didnt give you the whole story because I didnt think it was relevant. I was VERY WRONG.

    In fact, you are all correct that the CLex class that I provided does allow access to the string vector, m_vs, and it doesnt even need to be public.

    What I failed to disclose was that I had been trying to access CLex::m_vs through another class, and that is where it fails.

    Code:
    class CParsMat
    {
    public:
       CParsMat(){}
       virtual ~CParsMat(){}
    
    // Attributes
    private:
       CLex m_lex;
       long m_nrows, m_ncols;
       vector<string> m_V;
    
    // Implementation
    public:
       void DoParse(string s)
       {
          int k = 0;
          double dval = 0.0;
          m_V = m_lex.get_svals(); 
          //...
       }
       
       //...
    };
    It is in the CParsMat:oParse() function that m_V has no size, which is what m_lex.get_svals() returns.

    Now I am pretty sure that I have failed to instantiate something . I did do as Sam Hobbs suggested and step through the process, but I still can't figure out where my vector went.

    FWIW, I canned the second class and just built everything into the first (CLex) class and it now works OK. Allowing CParsMat to inherit from CLex didnt seem to make any difference, nor did instantiating a CLex pointer in CParsMat rather than just having CLex a member function.

    Clearly, there is some basic principle of C++ that I have failed to grasp. If any of you care to point that failing out, I would be most grateful.

    Thanks to all.

    Mike
    mpliam

  9. #9
    Join Date
    Jan 2002
    Location
    Scaro, UK
    Posts
    5,940
    Hey guys, are you telling me that the copy constructor for vector isn't protected or private ?

    Wow, that's rather amazing considering the speed implications.

    For your information : you should AT LEAST be passing by reference i.e.

    Code:
    vector<string> &get_svec() { return m_vs; }
    Why ?

    The above approach doesn't do any copying - it's sort of like passing a pointer. I'm sure MSDN has a much better explanation of references than I can possibly do here, so I suggest you look them up if you don't already know.

    However your first method will COPY the entire vector over, which has a major overhead.

    Any array copy constructors should be at least protected and very possibly private in my opinion to stop things like this from happening.

    Oh and as to your problem, it is likely to exist in code that you haven't shown I'm afraid.

    Why not put breakpoints throughout the code and just step through it doing a simple task ?

    In this case I find '#if 0 ... #else ... #endif' statements are highly useful since you can block out code without having to comment the whole thing out

    Darwen.

  10. #10
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,721
    In your CParsMat class, where do you call the parse()
    function of the CLex class to add to the m_vs vector of
    that class ?

    I suspect you did something like this :

    Code:
    CLex lex;
    lex.parse("123...");
    
    CParsMat parsmat;
    that is the CLex object that you added strings to was not
    the CLex object that is contained in the CParsMat class.

  11. #11
    Join Date
    May 2002
    Posts
    1,798
    That's exactly right, Phil. But m_lex is the CParsMat member variable, CLex m_lex. The way I thought of it, as soon as I instantiated CParsMat, it automatically instantiated the CParsMat member variable CLex m_lex. So that using m_lex.parse(string s) should result in the string being set to the CLex::m_vs (vector<string> m_vs of CLex). In fact, it does, but only in the function CLex:arse(string s). when accessed via the CParsMat member variable, m_lex. Once out of CLex:arse(string s) function scope, the vector is no longer of any size.

    I thought that the vector should persist and be accessible, but it's not. You're undoubtedly correct in that I have somehow instantiated the wrong (some other) vector, but I dont really get it.

    Mike
    mpliam

  12. #12
    Join Date
    Apr 1999
    Posts
    27,449
    Originally posted by darwen
    Hey guys, are you telling me that the copy constructor for vector isn't protected or private ?
    Yes, and I'm glad it is.

    Consider what you want as an alternative --

    1) You have to write a copy contructor and op = for your class every time you have a vector as a member if you intend to have a container of objects of this class. If not, you get the compiler error that literally scores of posters on CodeGuru have encountered.

    2) A private constructor/ op = implies that the class is not copyable whatsoever, unless you know first-hand that you can implement a copy constructor/op = in a derived class (and vector should not be derived from).

    3) The convenience of saying
    Code:
    std::vector<int> vec1, vec2;
    //...
    vec2 = vec1;
    is well worth the public assignment operator and copy ctor.

    There are other reasons, but I won't go into them now.
    Any array copy constructors should be at least protected and very possibly private in my opinion to stop things like this from happening.
    Let the programmer decide. I don't want the container class deciding for me that "copying is inefficient, so I won't let you do it". If I believe that program mainentance outweighs efficiency, let me have my way.

    Also, the latest or upcoming version of VC 7.x is going to finally introduce NRVO optimization. If you are not aware of what it is, here is an example:
    Code:
    #include <vector>
    #include <string>
    std::vector<std::string> foo()
    {
        std::vector<std::string> f;
        //...
        return f;
    }
    Even though the return is a vector, the compiler can optimize the copy so that no copying is done. This is one optimization technique (I believe maybe the only optimization) that is defined in the current C++ standard. It's too bad that VC 6 and early/current versions of VC 7 do not support it, but it will be implemented in a future version (it currently exists in many other compilers).

    So all the talk of returning vectors by value will be moot in terms of "expensive" copying.

    Regards,

    Paul McKenzie
    Last edited by Paul McKenzie; December 13th, 2003 at 03:41 PM.

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