1

I am trying to overload the [] operator so that when a programmer wishes to retrieve and set specific characters of a string, which is contained in a spot of a vector, the number passed into [] would reference the ith char from the beginning of the vector, to the end.

For example: Here is a vector. Starting from the beginning (0), the contents are as follows:

dog
cat
parrot

where 'dog' is the first string in the vector, and 'parrot' is the last. I want the [] operator to function as follows:

searchable_vector vec;
vec.push_back("dog");
vec.push_back("cat");
vec.push_back("parrot");

std::cout << vec[3] << " should say 'c' ";

Here is my searchable_vector.hpp:

#pragma once
#include <vector>
class searchable_vector : public std::vector<std::string>
{
 public:
    char& operator [] (int n);
 private:
    std::vector<std::string> vector;
};

Here is searchable_vector.cpp:

char& searchable_vector::operator[] (int i)
{
    // 'for each' string in vector member, count 
    // the length and add it to a counter until
    // the counter is at desired 'length' (given from i)
    unsigned int counter = 0;
    unsigned int spot_in_string = 0;
    std::string holding_string = "";

    std::vector<std::string>::iterator it;
    it = vector.begin();

    while (it != vector.end() && counter != i)
      {
          if (counter == i) // it is where it needs to be
              break;
          else 
          {
              spot_in_string = it->length() - 1;
              if (counter != 0)
                  counter += spot_in_string + 1;
              else
                  counter += spot_in_string;

              if (counter < i) // look in next string
              {
                it++;
              }
              else if (counter > i)
              {
                while (counter != i)        // go 'back' one at a time
                {
                  counter--;
                  spot_in_string--;
                }
                break; //should break out of master while loop
              }
          }
      }
      holding_string = *it;
      return holding_string[spot_in_string];
}

I wouldn't worry too much about the logic going on inside of this code, but I don't think I've done something right with overloading, as I get a Linker 2019 error (using Visual Studio) in my test file for unit testing:

TEST_CASE("Test searchable_vector class [] operator", "[searchable_vector]")
{
    searchable_vector vec;
    vec.push_back("dog");
    vec.push_back("cat");
    vec.push_back("parrot");
    char result = vec[3];
    REQUIRE(result == 'c');
}

The error reads:

LNK2019 unresolved external symbol "public: char & __cdecl 
searchable_vector::operator[](int)" (??Asearchable_vector@@QEAAAEADH@Z) 
referenced in function "void __cdecl ____C_A_T_C_H____T_E_S_T____2(void)" (?
____C_A_T_C_H____T_E_S_T____2@@YAXXZ)   unit_tests

followed by the directory which holds my VM_Module.obj

I think it's just something elementary with my over loading, not the logic itself. If that was broken this it should still link and run, just behave badly or crash.

Any constructive feedback would be appreciated.

Also, the reason I want to overload this is so that the code I am about to write will expect the searchable_vector object to behave as mentioned, returning the ith char in the vector, and if successfully implemented, should be clean and easy to write. Thanks.

Caleb W.
  • 129
  • 2
  • 11
  • I believe it has something to do with the way I am returning a char& from the operator. When commenting out "char result = vec[3];" and the REQUIRE line of the test, everything compiles. I just thought I would need to return the address of the char so that I could also set chars of the vector like "vec[44] = 't'; – Caleb W. Mar 25 '18 at 20:11
  • 2
    Perhaps unrelated, but bad error: Besides your linker problem you return a reference to a local. You return a `char&` which points to a char of the local var `std::string holding_string`. Suggestion: Warning level 4, warnings as errors. – user2328447 Mar 25 '18 at 20:23
  • @user2328447 very good point! I just don't know how else I could use the operator to SET characters in the vector ( like vec[6] = 'g'; ). perhaps that would mean i need to overload the operator= for....the vector class? – Caleb W. Mar 25 '18 at 20:31
  • Most likely searchable_vector.cpp is just not being included in your program. Make sure it's part of your IDE's "project". – aschepler Mar 25 '18 at 20:37
  • 1
    Returning a reference should be ok, but not to a local ;) You could remove `holding_string` completely and replace the last two lines by `return (*it)[spot_in_string]`. This would return a valid reference to a char in a string your vector is holding. Anyway, when returning a reference you will have to take care about faulty insertion, since in that case you won't be able to return anything valid. E.g. in case of index out of range. The best approach would probably be to throw a `std::out_of_range`, but at least there should be an assertion. – user2328447 Mar 25 '18 at 20:40
  • You don't want to inherit from std::vector – Jorge González Lorenzo Mar 25 '18 at 20:54
  • Okay changed return line to @user2328447 's suggestion. Love that solution. I've included searchable_vector.hpp – Caleb W. Mar 25 '18 at 21:01
  • Possible duplicate of [What is an undefined reference/unresolved external symbol error and how do I fix it?](https://stackoverflow.com/questions/12573816/what-is-an-undefined-reference-unresolved-external-symbol-error-and-how-do-i-fix) – 1201ProgramAlarm Mar 25 '18 at 22:26
  • @1201ProgramAlarm I don't know that it is NOT a duplicate, or that that post solved my issue. I can say I will add cmake as a tag, since my solution was to do with including the new source and heading in CMakelists.txt. – Caleb W. Mar 26 '18 at 15:52

1 Answers1

1

The issue with the linking was because I didn't add the header and source to my CMakelists.txt for CMake to 'know about' i guess. After changing that I re-ran cmake and it all worked.

As far as dangers of inheriting from vector, yeah i learned about that when I discovered there was nothing in my private vector. this was because when I called

vec.push_back("somestring");

in my tests, push_back() (inherited from vector) stored the values to the INHERITED 'collection' if you will, rather than my private one. So I just deleted my private vector since it was unnecessary, and changed my cpp a bit so it is set to

it = this->begin();

rather than

it = vector.begin();

So it is working now :)

Caleb W.
  • 129
  • 2
  • 11