Thread: stl::vector pass by reference

  1. #1
    Registered User
    Join Date
    Jul 2012
    Posts
    87

    stl::vector pass by reference

    I noticed that I had to pass by reference in order to change the actual vector object I used. But curious as to why for the print_table, I don't have to pass by reference, BUT for the trivial clear_table function I need to (otherwise Frank doesn't get removed from the list).

    I'm just building trivial open addressing hash table using double hashing.

    Code:
    //FNV string hash fcn (src:http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx)
    //Helper fcn used in open_address_insert/remove/search operations
    unsigned int fnv_hash(const void* key, int len)
    {
       const unsigned char* p = static_cast<const unsigned char*>(key);
       unsigned int h = 2166136261;
       
       for (int i = 0; i < len; i++)
         h = (h * 16777619) ^ p[i];
       
       return h;
    }
    
    //note: no duplicates, no values (very simplified double hashing method of open addressing)
    void insert_via_double_hashing(vector<string>& list, const string& key)
    {
        size_t size = list.size();
        size_t cur_bucket = fnv_hash(key.c_str(), key.size() ) % size;
        size_t second_hash_fcn = (fnv_hash(key.c_str(), key.size() ) % (size - 1) ) + 1;//NB: 2nd hash fcn is a step size
        
        for ( size_t i = 0; i < list.size(); ++cur_bucket )
        {    
            if ( list[cur_bucket] == "deleted" || list[cur_bucket] == "" )
            {
                list[cur_bucket] = key;
                // cout << list[cur_bucket] << endl;
                cout << "SUCCESS. Key:[" << key << "] inserted @:[" << cur_bucket << "]." << endl;
                return;
            }
            
            cur_bucket = (cur_bucket + second_hash_fcn) % size;
        }
    }
    
    
    void print_table(vector<string> v)
    {
        cout << "PRINTING TABLE..." << endl;
        
        for ( size_t i = 0; i < v.size(); ++i )
            cout << v.at(i) << ", ";
        cout << endl;
    }
    
    //NB:redundant, but to hide details
    void clear_table(vector<string>& v)
    {
        v.assign(10,"");
    }
    
    int main()
    {
      vector<string> namebook;
        namebook.assign(10,"");
    
        namebook[2] = "Frank";
        
        for ( size_t i = 0; i < namebook.size(); ++i )
            cout << namebook.at(i) << ", ";
        cout << endl;
        
        clear_table(namebook);
        
        insert_via_double_hashing(namebook, "joe");
      
      return 0;
    }
    EDIT: or I shouldn't worry since I didn't build the vector class and so the details of how it knows is part of compiler and library writer's job?
    Last edited by monkey_c_monkey; 07-26-2012 at 04:49 PM.

  2. #2
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Quote Originally Posted by monkey_c_monkey View Post
    I noticed that I had to pass by reference in order to change the actual vector object I used. But curious as to why for the print_table, I don't have to pass by reference, BUT for the trivial clear_table function I need to (otherwise Frank doesn't get removed from the list).
    Functions (II) - C++ Documentation

    If you don't pass by reference, you pass by value. Passing by value means that a copy of the vector is used within the function. Any modifications are modifying the copy, not the original.
    Passing by reference passes the original vector, so modifications are made to the vector.

    clear_table needs to be able to modify the vector, so you have to pass by reference.
    print_table doesn't modify the vector -- it just reads from it. So passing by value works. However a new vector object has to be constructed and all the values copied into it. It's not efficient to do this when you could just pass a reference.

    Quote Originally Posted by monkey_c_monkey View Post
    EDIT: or I shouldn't worry since I didn't build the vector class and so the details of how it knows is part of compiler and library writer's job?
    You should worry! The same rules apply to classes you've written yourself, and to plain data types. The implementation of vector is indeed the concern of the library, but passing it by reference or value is part of using it.

  3. #3
    Registered User
    Join Date
    Jul 2012
    Posts
    87
    I understand what pass by value, by reference, by address all mean. What I forgot and you're post reminded me was that we can pass an entire object by value (so instance of a class, struct) which is inefficient b/c of size (so copy all members etc as you said). That was the part I didn't know for why we can just pass by value for print_table, I forgot I was dealing w/ an object, since I am so used to using arrays (not the STL containers array, just plain old array) as in:

    Code:
    void print_list(string* list, size_t size)//need to pass array by address in this case
    {
      for ( size_t i = 0; i < size; ++i )
       cout << list[i] << ", ";
      cout << endl;
    }
    
    int main()
    { 
      string list[10] = {""};
      size_t size = sizeof(list)/sizeof(list[0]);
      print_list(&list[0], size);
    
     return 0;
    }
    So you notice how for this print list, I need to pass by address. Appreciate it.
    Last edited by monkey_c_monkey; 07-26-2012 at 06:04 PM.

  4. #4
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    I'm not sure if you're asking a real question. The reason you have to pass by address for arrays is because arrays are not copyable objects in C++. You really have no other choice. However, I can complicate what I just said... if you have an array as a class member (std::array or just T[N]) then a new array is constructed and the elements are copied in for you.

  5. #5
    Registered User
    Join Date
    Jul 2012
    Posts
    87
    Actually, I think for my clear_table function, it MUST be pass by reference and not by value. B/c I tried it, and it doesn't reset to empty string b/c I'm guessing copy constructor creates a completely new copy of the vector object in main so all the emptying gets MODIFIED in the copy.

  6. #6
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Yes, for your clear_table function you must pass by address. smokeyangel already explained.

    Then, you asked why you have to pass arrays by their address, even when you write something that shouldn't necessarily need it, like the print_table function. I tried to answer that.

  7. #7
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Yes - if you expect modifications in the function to affect the vector passed from main, you MUST pass by reference.

    Quote Originally Posted by monkey_c_monkey
    I understand what pass by value, by reference, by address all mean. What I forgot and you're post reminded me was that we can pass an entire object by value (so instance of a class, struct) which is inefficient b/c of size (so copy all members etc as you said). That was the part I didn't know for why we can just pass by value for print_table, I forgot I was dealing w/ an object, since I am so used to using arrays (not the STL containers array, just plain old array) as in:
    I don't quite understand what you're asking. As whiteflags said, arrays aren't copyable objects so you can't pass by value.
    You can pass an array by reference but you need to specify the size of the array:
    Code:
    void print_list(string (&list)[10], size_t size)
    But I had to google this syntax and haven't ever had any reason to use it.

    Don't think that was what you were asking. What were you asking?

  8. #8
    Registered User
    Join Date
    Jul 2012
    Posts
    87
    Yes, for your clear_table function you must pass by address. smokeyangel already explained.
    I didn't read carefully, thanks all.

  9. #9
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    On a side note your print table should actually use a const reference since it does not modify the object and to avoid the unecessary copy. Likewise nothing is gained by using at() in print_ table as opposed to a simple index since the number of iterations is determined by vector::size() which ensures that all indices within the loop will be within range of the vector. Nothing is lost however by using at() but I thought I would mention it.
    Last edited by VirtualAce; 07-27-2012 at 08:21 PM.

  10. #10
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Also, the at member function will throw an exception if you access out of bounds indexes. This may come in handy sometimes.
    The index operator will yield undefined behavior if you do out-of-bounds access. However, most compilers (at least the ones I know) will break in debug mode if you do, in order to help you debug.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 02-14-2012, 07:45 PM
  2. Pass by reference
    By jrice528 in forum C++ Programming
    Replies: 4
    Last Post: 10-30-2007, 01:02 PM
  3. Pass by reference vs pass by pointer
    By Non@pp in forum C++ Programming
    Replies: 10
    Last Post: 02-21-2006, 01:06 PM
  4. pass by reference .... HELP!!
    By NamelessNoob in forum C++ Programming
    Replies: 19
    Last Post: 02-15-2006, 12:50 PM
  5. pass be reference versus pass by value
    By Unregistered in forum C++ Programming
    Replies: 2
    Last Post: 08-01-2002, 01:03 PM