Vector of user-defined types

May 11, 2019 at 7:42pm
closed account (S1URSL3A)
I'm fairly new to C++ and I'm currently in the process of learning it.
I'm writing a text adventure game (using Visual Studio 2019) where the user types in what they want to do (e.g. "go south," "get sword," etc.). I'm using a vector "inv" of my struct "item" for the player's inventory. I want it to be where the user enters "drop" followed by the name of the item they want to drop, and the item gets erased from their inventory (after first being added to the room's vector of items). But when I tried to implement this, I got a compile-time error with this message:

Error C2280 'item &item::operator =(const item &)': attempting to reference a deleted function TextAdventure C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\include\xutility 2086

Using multi-line commenting, I narrowed it down to every statement where I call the vector's "begin()" member function. Here is an example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <vector>

struct item {

	const std::string name{},desc{};
};

struct room {

	const std::string name{},desc{};
	std::vector<item> cont{};
};

std::vector<item> inv{{"sword","(sword desc)"},{"lantern","(lantern desc)"}};

room exampleRoom{{"kitchen"},{"(kitchen description)"},{}};

int main() {

	std::string word{};
	std::cin >> word;

	for (char i{0}; i < inv.size(); ++i)
		if (inv[i].name == word) {

			exampleRoom.cont.push_back(inv[i]);
			
			// The error stops when I comment out the following line:
			inv.erase(inv.begin() + i);

			std::cout << "The " << word << " is now on the ground.\n";
		}
}

Does the error occur because the vector contains user-defined types? How can I get this to work? Any help would be greatly appreciated. Thanks.
Last edited on May 11, 2019 at 10:02pm
May 11, 2019 at 8:23pm
You need to break out of the loop after you move the item. Also, don't put {} after std::string or std::vector declarations. They are initialized by default. And don't use char as an index to a vector. Use an int at least. It's probably most correct to use size_t.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include <iostream>
#include <vector>

struct item {
    std::string name,desc;
};

std::ostream& operator<<(std::ostream& os, const item& it) {
    return os << it.name << " : " << it.desc;
}

struct room {
    std::string name, desc;
    std::vector<item> cont;
};

std::vector<item> inv{
    { "sword",   "(sword desc)" },
    { "lantern", "(lantern desc)" }
};

room exampleRoom{
    {"kitchen"}, {"(kitchen description)"}, {}
};

int main() {

    std::string word;
    std::cin >> word;

    for (size_t i{0}; i < inv.size(); ++i)
        if (inv[i].name == word) {
            exampleRoom.cont.push_back(inv[i]);
            inv.erase(inv.begin() + i);
            std::cout << "The " << word << " is now on the ground.\n";
            break;
        }

    std::cout << "\nInventory:\n";
    for (const item& it: inv) std::cout << it << '\n';
    std::cout << "\nRoom:\n";
    for (const item& it: exampleRoom.cont) std::cout << it << '\n';
}

May 11, 2019 at 9:17pm
closed account (S1URSL3A)
Okay, so I did the things you said to do:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <vector>
struct item {

	const std::string name,desc;
};

struct room {

	const std::string name,desc;
	std::vector<item> cont;
};

std::vector<item> inv{{"sword","(sword description)"},{"shield","(shield description)"}};
room exampleRoom{{"kitchen"},{"(kitchen description)"},{}};

int main() {

	std::string word{};
	std::cin >> word;

	for (size_t i{0}; i < inv.size(); ++i)
		if (inv[i].name == word) {

			exampleRoom.cont.push_back(inv[i]);
			inv.erase(inv.begin() + i);

			std::cout << "The " << word << " is now on the ground.\n";
			break;
		}
}

But I'm still getting the same error.
May 11, 2019 at 9:33pm
I forgot to mention that I also removed the "const" on your strings.
The erase method of std::vector needs to be able to copy the items to new positions (like removing an element from an array). So it needs the operator= method of item. But making the strings const causes the operator= method to be "deleted" so you don't get the default method.
Last edited on May 11, 2019 at 9:39pm
May 11, 2019 at 9:43pm
closed account (S1URSL3A)
That did it! Thank you so much for your help! I'll be sure to keep those in mind for the future. There's one other thing I could use some help with. How can I use std::sort() to sort the inventory by item name?
Last edited on May 11, 2019 at 10:16pm
May 11, 2019 at 10:28pm
The sort has a version that takes third argument:
http://www.cplusplus.com/reference/algorithm/sort/

For example:
1
2
3
sort( inv.begin(), inv.end(),
      [](auto& lhs, auto& rhs){return lhs.name < rhs.name;}
    );
May 11, 2019 at 11:01pm
closed account (S1URSL3A)
Thank you, everyone, for all your help!
Topic archived. No new replies allowed.