1

Help me out. I know what I need to do but I am not a C++ developer.

I need the GetItem to return a reference so that the SetName function value takes. I think I need to add & and * somewhere.

This is part of a much larger file and this silly thing is tripping me up:

#include <iostream>
#include <vector>

using namespace std;

class Item
{
    public:
    Item(string Code, string Name)
    {
        _code = Code;
        _name = Name;
    }
    void SetName(string Name) { _name = Name; }

    string GetCode() { return _code; }
    string GetName() { return _name; }

    private:
    string _code;
    string _name;
};
class SomeClass
{
    public:
        SomeClass()
        {

        }
        void AddItem(string Code, string Name)
        {
            Item item(Code, Name);
            _items.push_back(item);
        }
        Item GetItem(string Code)
        {
            for (int i = 0; i < _items.size(); i++)
            {
                if (_items[i].GetCode() == Code)
                {
                    return _items[i];
                }
            }
        }
    private:
        vector<Item> _items;
};

int main()
{
    SomeClass someClass;
    someClass.AddItem("001","Name001");
    cout << someClass.GetItem("001").GetName() << endl;
    someClass.GetItem("001").SetName("Name001aaaaa");
    cout << someClass.GetItem("001").GetName() << endl;
    return 0;
}
Joel Bodenmann
  • 2,152
  • 2
  • 17
  • 44
Shaun Vermaak
  • 301
  • 2
  • 13
  • 2
    Set the return type of `GetItem` to `Item&`. – L. F. Mar 25 '20 at 09:18
  • 2
    Your program has undefined behaviour if the item isn't found. It would have that even if you returned a reference. – molbdnilo Mar 25 '20 at 09:19
  • 1
    compare to how standard algorithms handle this situation. Using iterators and returning the end iterator in case the element cannot be found is a welll established pattern. Returning a reference when "no element" is a possible return is a no-go – 463035818_is_not_an_ai Mar 25 '20 at 09:24
  • btw in case the element isnt found your `GetItem` method is missing a `return` – 463035818_is_not_an_ai Mar 25 '20 at 09:25
  • Thank you L.F. I knew it was something like that and I tried a bunch of combinations. Thank you for saving me frustration – Shaun Vermaak Mar 25 '20 at 09:26
  • 1
    your title is misleading. Unless I misread the question you want to return a reference to one element not the whole vector – 463035818_is_not_an_ai Mar 25 '20 at 09:28
  • How would I use an iterator in this situation? – Shaun Vermaak Mar 25 '20 at 09:32
  • Unrelated: Have you thought about using a [`std::multimap`](https://en.cppreference.com/w/cpp/container/multimap) for this instead? – Ted Lyngmo Mar 25 '20 at 09:54
  • frankly, it is not clear what is the purpose of `SomeClass`, it seems to be just a `std::vector` and for a `std::vector` you can use `std::find` that does return an iterator. If you want you can make `GetItem` return the iterator returned from `std::find` with the usual precautions (iterators can get invalidated) – 463035818_is_not_an_ai Mar 25 '20 at 09:56
  • ps: it would be `std::find_if` in your case. See eg here: https://stackoverflow.com/questions/15063301/how-can-i-find-an-object-in-a-vector-based-on-class-properties – 463035818_is_not_an_ai Mar 25 '20 at 09:59

2 Answers2

3

You only need to change two lines of code:

    Item& GetItem(string Code) // <-- return by reference
    {
        for (int i = 0; i < _items.size(); i++)
        {
            if (_items[i].GetCode() == Code)
            {
                return _items[i];
            }
        }
        throw std::out_of_range; // <-- handle error
    }

The return of _items[i] is a reference already, so returning by reference like this just continues to pass the return type on, without copying the value.

But as others are pointing out, you need to be very careful about error-handling. C++ references must always reference a valid object, so the only way to handle errors is by exceptions.

Callers will now also need to use the reference type:

Item& r = x.GetItem(n);

If instead a caller does this:

Item v = x.GetItem(n); // !!!

Then v will be a copy of the item.

tenfour
  • 36,141
  • 15
  • 83
  • 142
  • "the only way to handle errors is by exceptions" - No. There are other options. You could, for example, return a `std::optional>` and then return `std::nullopt` in the failure case. – Jesper Juhl Mar 25 '20 at 15:21
1

you have one main problem that is like @molbdnili wrote in the comment in function

Item GetItem(string Code)

return item buy value buy you don't have a return statement when the code is not in you vector Il would don something like that

bool GetItem(string Code,Item& i)
   {
    for(auto& e:_items )
    {
        if(e.GetCode() == Code)
        {
            i = e;
            return true;
        }
    }
    return false;
    }

but if you want the return statement the be the item you have two options 1)

 Item* GetItem(string Code)
 {
    for(auto& e:_items )
    {
        if(e.GetCode() == Code)
        {
             return &e;
        }
    }
    return nullptr;
  }

but you need to check in your code for null in the return the second method is

 Item& GetItem(string Code)
 {
            for(auto& e:_items )
            {
                if(e.GetCode() == Code)
                {
                    return e;
                }
            }
            throw std::out_of_range("not code "+ Code);       
 }
yaodav
  • 1,126
  • 12
  • 34