problem w/ iterator looping through a vector


DevX Home    Today's Headlines   Articles Archive   Tip Bank   Forums   

Results 1 to 7 of 7

Thread: problem w/ iterator looping through a vector

  1. #1
    Join Date
    Jul 2005
    Posts
    22

    Question problem w/ iterator looping through a vector

    Hello all. I'm having a problem w/ STL, which I must admit, I am in the process of learning. Here is as small a code snippet as I can give that illustrates the source of my confusion. ANY help at all would be much appreciated, Thanks. So here's a ripped down version of some of the misbehaving code:

    // A.hh (and other methods declarations & includes/namespace directive)
    class A {
    public:
    A() : name( "none"), number( 1 ), sizes( vector<double>::vector( ) ) { }

    A( const string s, const unsigned int i, const vector<double> v) :
    name( s ), number( i ), sizes( v ) { }

    vector<double> getSizes( ) const;

    private:
    string name;
    unsigned int number;
    vector<double> sizes;
    };

    // A.cc (and other methods definitions)
    vector<double> A::getSizes( ) const { return sizes; }

    // Driver.cc
    #include "A.hh"

    main() {
    vector<double> v( 5, 2.3 );
    vector<double>::iterator iv;

    A a = A::A( "no matter", 2, v);

    for( iv = a.getSizes().begin(); iv != a.getSizes().end(); iv++ )
    cout << *iv << endl;

    cout << endl;

    for ( int i = 0; i < a.getSizes().size(); i++)
    cout << a.getSizes( )[ i ] << endl;

    return 0;
    }

    And here's what the output looks like:
    $ a.out
    1.87046e-301
    2.3
    2.3
    2.3
    2.3

    2.3
    2.3
    2.3
    2.3
    2.3
    $

    This has just struck me as really strange and I'm not sure what I'm doing wrong as far as working w/ iterators and vectors. Fyi (if this matters), I am compiling this with g++ version 3.3 on a Mac G5.

  2. #2
    Join Date
    Nov 2003
    Posts
    4,118
    OK, before diving deep into iterators, let's review your class:

    Code:
    class A 
    {
    public:
    A() : name( "none"), number( 1 ), sizes( vector<double>::vector( ) ) { }
    
    A( const string s, const unsigned int i, const vector<double> v) :
    name( s ), number( i ), sizes( v ) { }
    
    vector<double> getSizes( ) const;
    
    private:
    string name;
    unsigned int number;
    vector<double> sizes;
    };
    If the vector member of A is meant to be deault constructed, you should omit the initializer sizes( vector<double>::vector( ) from the constructor initialization list of class A. It doesn't cause much harm but it's misleading, and useless.

    Code:
    vector<double> getSizes( ) const;
    This is a more serious issue. Don't ever return a vector by value from a function. Not only is this a performance killer, you will end up looking for subtle bugs that have to do with the construction of temporaries. Besides, a function called getSizes should return an int -- the size of something. If it returns a full blown vector, it should be named accordingly, and the vector had better be returned by reference.

    Now to iterators. The common idiom is to use the begin() and end() members of an STL container when you want to traverse its elements:
    Code:
    vector <double>::iterator it;
    for (it=vec.begin(); it<vec.end(); ++it)
    {
     cout << *it<<endl;
    }
    Danny Kalev

  3. #3
    Join Date
    Jul 2005
    Posts
    22
    That was helpful. Thanks a lot. So I think the problem is with my get and set methods for stl containers. It doesn't like when I just write:

    vector<double>& A::getVector() const { return sizes; }

    it complains:

    could not convert `this->A::sizes' to ` std::vector<double, std::allocator<double> >&'

    Also, I thought the point of returning a reference was (speed of course) the ability to alter the return value (and chaining) but it appears to me that you're saying for the standard containers you sould always be returning a reference. Is that right?

    Like I said, thanks a lot. I'm just getting back into C++ coding and when I learned it a while ago it was before STL was part of the language ....

  4. #4
    Join Date
    Nov 2003
    Posts
    4,118
    Quote Originally Posted by bpw1621
    That was helpful. Thanks a lot. So I think the problem is with my get and set methods for stl containers. It doesn't like when I just write:

    Code:
    vector<double>& A::getVector() const { return sizes; }
    it complains:

    could not convert `this->A::sizes' to ` std::vector<double, std::allocator<double> >&'
    The problem is with the const. a const member function can only return reference to const, which also answers your second question: the user cannot modify such a return value:

    Code:
    const vector<double>& A::getVector() const { return sizes; }
    //usage:
    const vector<double> & myvec=a.getVector();
    you can call all the const member function of myvec, including begin() and end(). However, you cannot modify it.
    Danny Kalev

  5. #5
    Join Date
    Jul 2005
    Posts
    22
    Danny ... you the MAN! I actually understand why what I wrote didn't work and I doubt it will be a mistake I'm likely to repeat (after a day or two of toil before joining and posting on this site). Thank you so much ...

    I had a general question about something you wrote in your first post that I was hoping you could elaborate on. As if quoting a commandment, you said that one should never return a vector (and I'm guessing any other stl container) by value because of (preformance issues, which I was aware of and ...) problems with the construction of temporaries. So if you could spell out why exactly you feel that way (other than preformance issues which would accompany passing any class object by value) that would be a(nother) really big help.

    In the same vein, suppose you wanted a member function to return a private vector member of some class and be able to modify the returned vector without modifying the actual class (i.e., its private vector member). Would you implement this as returning a const reference to the member vector, doing a copy to a local (non-const) vector and then modifying the copy? That sound extremely inefficient (as opposed to passing back the vector by value and modifying that). Any thoughts on that would be great ...

    Sorry for the diatribe but I'm getting pretty excitied about learning the language as it is now ... so thanks, thanks, THANKS!!!

  6. #6
    Join Date
    Jul 2005
    Posts
    22
    Ok, so I guess I was mistaken about something.

    Code:
    class A {
    public:
    A( vector<double> temp ) : v( temp ) { }
    vector<double>& getVector() { return v; }
    
    private:
    vector<double> v;
    };
    
    main() {
    vector<double> v(3,1), vv;
    A a = A::A( v );
    
    for( int i = 0; i < a.getVector().size(); i++ )
      cout << a.getVector()[ i ] << endl;
    cout << endl;
    
    vv = a.getVector();
    vv.push_back( 7 );
    
    for( int i = 0; i < a.getVector().size(); i++ )
      cout << a.getVector()[ i ] << endl;
    cout << endl;
    
    for( int i = 0; i < vv.size(); i++ )
      cout << vv[ i ] << endl;
    
    return 0;
    }
    and then this comes out:

    $ a.out
    1
    1
    1

    1
    1
    1

    1
    1
    1
    7

    So I was under the impression that if you returned the reference to the private member then the vv becomes an alias for the private member v of the object a ... and that changes to vv changed the a.v ... however, this didn't happen so maybe this is really the solution to the problem I brought up in my last post. Can you (anyone of course ... although Danny is the only one who is replying to these posts so far ... thanks again) elaborate on why this occurs in the way it did rather than the way I thought it would? Don't worry ... I'm sure I'll let this thread die soon enough ... but it's been sooooo helpful to me (was stuck for two days before my first post) ...

  7. #7
    Join Date
    Nov 2003
    Posts
    4,118
    Quote Originally Posted by bpw1621
    I had a general question about something you wrote in your first post that I was hoping you could elaborate on. As if quoting a commandment, you said that one should never return a vector (and I'm guessing any other stl container) by value because of (preformance issues, which I was aware of and ...) problems with the construction of temporaries. So if you could spell out why exactly you feel that way (other than preformance issues which would accompany passing any class object by value) that would be a(nother) really big help.
    the problem is that whenever you call such a member function and use its return value to call a member function of the vector, say

    a.getVec().size(); //getVec returns a vector by value

    You cause a full blown copy of the vector to be constructed and destroyed immediately after executing the size() member function. This is terribly inefficient, especially if you're using this expression a loop. Another problem is that calling member functions that are supposed to modify the vector, say push_back, operate only on the temp copy, which is immediately destroyed afterwards.

    Quote Originally Posted by bpw1621
    In the same vein, suppose you wanted a member function to return a private vector member of some class and be able to modify the returned vector without modifying the actual class (i.e., its private vector member). Would you implement this as returning a const reference to the member vector, doing a copy to a local (non-const) vector and then modifying the copy? That sound extremely inefficient (as opposed to passing back the vector by value and modifying that). Any thoughts on that would be great ...
    Actually, I would question this design to begin with. A class shouldn't return a vector in general; if the vector is a private data member, then it's an implementation details that clients (i.e., users of the class) shouldn't depend on' let alone access. If you want to modify the vector, you should define additional member functions in class A that deal with A's internal member instead of letting external clients poke with the internals of class A. It's OK to return scalara values such as the size of the vector or a particular element thereof. However, if you find yourself writing code that returns a full-blown vector (either by value or by reference), this design should be looked at with suspicious. This isn't OOP.
    Danny Kalev

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
HTML5 Development Center
 
 
FAQ
Latest Articles
Java
.NET
XML
Database
Enterprise
Questions? Contact us.
C++
Web Development
Wireless
Latest Tips
Open Source


   Development Centers

   -- Android Development Center
   -- Cloud Development Project Center
   -- HTML5 Development Center
   -- Windows Mobile Development Center