Reputation: 97
After searching google and stackoverflow for 2 days I haven't found anything yet
I was working with java about a year now and I decided to create a game on C++ for practice
In java this should work but in C++ it blows my mind.
I have this code
Item* inventory = new Item[24];
It's array (inventory) that holds Items
When I allocate dynamicly an array all of its postions are null? And if not, can I make them all null?
And thats the code for add an item at first empty position (pick up an item)
void Inventory::addItem(Item it){
if(isFull()){
cout << "Full inventory" << endl;
}else{
for(int i = 0; i<length; i++){
if(inventory[i] == nullptr){ // need this to work somehow
inventory[i] = it;
}
}
}
}
It needs to be array not a vector because it has fixed size
Upvotes: 2
Views: 6073
Reputation: 490108
Contrary to your final comment, this seems to be a perfectly reasonable application for std::vector
.
As it stands right now, you're trying to create an array of N objects, but then have some M of those actually be null/empty/nonexistent objects.
The reality is that this is not a fixed size collection at all. It's a variable sized collection up to some specified maximum. At a given time a player might be carrying 1 item or 10, but there's some maximum number of items they can carry. They're not, however, constantly carrying the maximum number of items, and some of those happen to be null items1.
Since what you're dealing with really is a variable sized collection (up to a specified maximum), std::vector
fits the bill perfectly. Since you're dealing with an Item
class, it's probably reasonable to assume that the actual items will be instances of concrete classes that derive from Item
. That being the case, you really need to store (some variety of) pointer in the array, not actual Item objects (Otherwise, every derived item you try to put into the array will be "sliced" to become an actual Item object, not a derived object, when it's stored in the array).
You can do that by creating a collection of unique_ptr
s (or various other other smart pointer types, such as shared_ptr
), but I'd generally recommend that in such a situation you consider the Boost ptr_vector
type instead.
As far as enforcing the size limit goes, you probably want to create a small wrapper class to handle this. It's not exactly a complex task, but it's clearly better to centralize that code in one place, not duplicate the size checking code everywhere you might add an item to an inventory.
template <class T>
class inventory {
ptr_vector<T *> items;
size_t max;
public:
inventory(size_t max) : max(max) {}
push_back(T *t) {
if (items.size() < max)
items.push_back(t);
}
// other miscellany here.
};
It's possible, however, that you don't have a polymorphic hierarchy of Item
s. Instead, you have just have a single, fixed type for all items in the inventory, each of which has a name and such. If that's the case (i.e., all Item
s are really the same type of object), there's no reason to mess with pointers or ptr_vector
. You really just want a std::vector<Item>
. Much like above, however, you undoubtedly still want to centralize the code to enforce the Inventory's maximum size (and probably provide other inventory-specific services as well).
Upvotes: 2
Reputation: 76240
When I allocate dynamicly an array all of its postions are null? And if not, can I make them all null?
There's no such a thing as a null object in C++, like there is in Java. You can have a nullptr
pointer, instead. In your case the objects are default constructed, and are therefore not null.
It needs to be array not a vector because it has fixed size
You generally do not want to dynamically allocate unless it is strictly necessary. Use an std::array
, if you really want a fixed sized array.
What I would suggest is to use an std::array
in combination with an std::unique_ptr
:
std::array<std::unique_ptr<Item>, 24> arr;
By default, all std::unique_ptr
s will be nullptr
. When you'll need to allocate an object you will able to do:
arr[i] = std::unique_ptr<Item>(new Item(...));
You can even create an alias for the smart pointer:
using item_ptr = std::unique_ptr<Item>;
that will help you rewrite your code as:
std::array<item_ptr, 24> arr;
arr[0] = item_ptr(new Item(...));
Alternatively you can also use boost::optional
(or std::optional
from C++14):
std::array<std::optional<Item>> arr;
You will be able to check if a specific i
element is "null" (in the Java sense) with:
if (arr[i])
// not null
and you'll be able to assign a value with:
arr[i] = Item(...);
and retrieve it with *arr[i]
, arr[i]->member_function(...);
or arr[i]->member_object
.
Upvotes: 6