C++ vector erase method delete my object - c++

I first get an object A from the vector, then I call the erase method to destroy that object in my vector because I don't need it anymore. However, from the debugger, I found that the object A I got before calling erase method is also destroyed. I don't understand that because I thought that what I got is a copy of that object and erase method should have nothing to do with my object A.
Code
Class Unit
Header file
#ifndef UNIT_H
#define UNIT_H
#include <iostream>
class Unit
{
protected:
int id;
public:
Unit::Unit(int num = -1);
virtual ~Unit() = default;
virtual int getID();
};
#endif
CPP file
#include "Unit.h"
Unit::Unit(int num)
{
id = num;
}
int Unit::getID()
{
return id;
}
Class Box
Header file
#ifndef BOX_H
#define BOX_H
#include <string>
#include <iostream>
#include "Unit.h"
class Box : public Unit
{
private:
std::string* type;
int* val;
public:
Box::Box();
~Box();
int getVal();
std::string getName();
int getID() override;
};
#endif
CPP file
#include <time.h>
#include "Box.h"
Box::Box() : Unit(5)
{
int tmp = rand() % 3;
if (tmp == 0)
{
type = new std::string("hp"); // health cur
val = new int(rand() % 10 + 1);
}
else if (tmp == 1)
{
type = new std::string("exp"); // skill level or health max
val = new int(rand() % 5 + 1);
}
else
{
type = new std::string("punish"); // minus health cur
val = new int(-1);
}
}
Box::~Box()
{
delete type;
delete val;
}
int Box::getVal()
{
return *val;
}
std::string Box::getName()
{
return *type;
}
int Box::getID()
{
return id;
}
main file
using namespace std;
int main()
{
Box test;
std::vector<Box> bag;
bag.push_back(test);
Box tmp = bag[0];
bag.erase(bag.begin() + 0);
cout << tmp.getVal();
system("pause");
return 0;
}
Below is the screenshot from the debugger and because I don't have 10 reputations, I can't display it directly.
before
after
As you can see, the "type" and "val" data member of class Box is modified.

Check out this page about the return type from the index call
http://en.cppreference.com/w/cpp/container/vector/operator_at
I believe that you may have a reference, not a different object.

Related

C++: calling function from vector object in main

I am trying to call printTotals() from main(). I tried person.printTotals() but it does not work because agent only calls functions within the vector STL. I checked other answers, such as C++ Calling Vectors from Function to Main and Using vector of user defined class type objects and How to create a vector of class objects in C++?.
I also checked my STL book, but this case it is not in there.
I have two questions:
Is there a way to call printTotals() outside of the constructor? Can I call it from main()? I want to keep my code clean and modular, but I am unable to access it outside of the constructor.
Each person has 3 neighbors consisting of Persons in a vector. I thought about declaring the neighbors vector like this, but was not sure:
vector<Person> neighbor
For a specific person with id = 3, how can I retrieve their second neighbor's voting status? Would it be:
person[3].neighbor[1].getPersonVotingStatus()?
This is my code:
Person.h
#include <iostream>
#include <string.h>
#include <vector>
class Person
{
public:
Person();
Person( std::vector<Person> person, maxPersons);
std::string getPersonVotingStatus(int ID);
void printTotals();
private:
std::string personName;
float personHeight;
int personID;
std::string isVoter;
vector<Person>neighbor; // <---
}
Person.cpp
#include <iostream>
#include <string.h>
#include <vector>
Person::Person()
{}
Person::Person(int pID, float pHeight, std::string pName, std::string isV)
{
personID = pID;
personHeight = pHeight;
personName = pName;
isVoter = isV;
}
Person::Person( std::vector<Person> person, int maxPersons)
{
for(int = 0; i < maxPersons; i++)
{
person[i].personID = i;
person[i].personHeight = i + 100;
person[i].personName = "testName";
if (i / 2 = 0) {
person[i].isVoter = "yes";
}
else {
person[i].isVoter = "no";
}
}
Person(person[i].personID, person[i].personHeight, person[i].personName, person[i].isVoter);
}
std::String getPersonVotingStatus( int ID)
{
return person[i].isVoter;
}
void printTotals( std::vector<Person> person)
{
int totalVoter = 0;
int totalNonvoter = 0;
for (int i = 0; i< person.size(); i++)
if (person[i].isVoter == "yes") {
totalVoter++;
}
else {
totalNonvoter++;
}
}
main.cpp
#include <iostream>
#include <string.h>
#include <vector>
int main()
{
int maxPersons = 10;
std::vector<Person> person;
Person obj( person, maxPersons);
person.printTotals(); // <--
return 0;
}
Try defining printTotals() as a static function:
class Person
{
public:
static void printTotals(std::vector<Person> person);
}
Then you can call it in main like this:
Person::printTotals(person);

How to create an empty vector of objects in C++? [duplicate]

This question already has answers here:
vector of class without default constructor
(3 answers)
Object array initialization without default constructor
(14 answers)
C++ compiler complaining about no default constructor
(1 answer)
Closed 2 years ago.
As I currently study Java in University but I am working on a C++ project. It is a text game in which I'm trying to create an empty vector of Item objects which I'm later going to add with the addItem(Item newItem) method of the Room object. The problem is that when in the constructor I try to set it so that every time a room is created, a new vector of Item objects is created with a capacity of the vector of 20, it gives me this error:
'Item::Item': no appropriate default constructor available
Here is the code:
Item.hpp:
#include <iostream>
#include <string>
#ifndef Item_HPP
#define Item_HPP
class Item {
std::string description;
public:
Item(std::string description);
std::string getDescription();
void setDescription(std::string description);
void use();
};
#endif
Item.cpp:
#include "Item.hpp"
Item::Item(std::string description) {
this->description = description;
}
std::string Item::getDescription() {
return this->description;
}
void Item::setDescription(std::string description) {
this->description = description;
}
void Item::use() {
std::cout << "You are using item: " << description << std::endl;
}
Room.hpp:
#include <iostream>
#include <string>
#include <vector>
#include "Item.hpp"
#ifndef Room_HPP
#define Room_HPP
class Room {
std::string description;
static const int MAX_ITEMS = 20;
std::vector <Item> items;
int numberOfItems;
public:
Room(std::string description);
std::string getDescription();
void addItem(Item newItem);
std::vector<Item> getItems();
Item getItem(std::string description);
};
#endif
Room.cpp:
#include "Room.hpp"
Room::Room(std::string description) {
this->description = description;
this->items = std::vector<Item>(20);
this->numberOfItems = 0;
}
std::string Room::getDescription() {
return this->description;
}
void Room::addItem(Item newItem) {
if (numberOfItems < MAX_ITEMS) {
this->items[numberOfItems] = newItem;
numberOfItems++;
}
}
std::vector<Item> Room::getItems() {
return this->items;
}
Item Room::getItem(std::string description) {
int i = 0;
bool found = false;
Item *target = NULL;
while (!found && i < numberOfItems) {
if (items[i].getDescription() == description) {
target = &items[i];
found = true;
}
++i;
}
return *target;
}
You can firstly just reserve() buffer for 20 elements and later add elements via push_back().
Room::Room(std::string description) {
this->description = description;
this->items = std::vector<Item>();
this->items.reserve(20);
this->numberOfItems = 0;
}
void Room::addItem(Item newItem) {
if (numberOfItems < MAX_ITEMS) {
if (numberOfItems == static_cast<int>(this->items.size())) {
this->items.push_back(newItem);
} else if (numberOfItems < static_cast<int>(this->items.size())) {
this->items[numberOfItems] = newItem;
} else {
// unsupported to create gap between items
}
numberOfItems++;
}
}

Trouble with printing C++ Hash Table

I'm pretty new to C++ and am trying to teach myself how to implement a hash table(I know I could use unordered_map, but I'm challenging myself). Right now I have a vector of structs(cell) that holds person-specific information. I have a PrintTable function that I want to use to print out each struct member of every item in the table. However, I can't seem to access the specific members of the struct(cell). What am I doing wrong here?
#include <iostream>
#include <string>
#include <vector>
struct cell
{
std::string name;
int age;
std::string weapon;
};
class HashTable
{
private:
std::vector<cell> *table;
int total_elements;
int getHash(int key)
{
return key % total_elements;
}
public:
HashTable(int n)
{
total_elements = n;
table = new std::vector<cell>[total_elements];
}
void SearchTheTable(int hashIndex);
void AddItem(std::string name, int age, std::string weapon);
void RemoveItem();
void PrintTable();
};
void HashTable::SearchTheTable(int hashIndex)
{
int x = getHash(hashIndex);
std::cout << x;
}
void HashTable::AddItem(std::string name, int age, std::string weapon)
{
cell newCell = { name, age, weapon };
table->push_back(newCell);
}
void HashTable::RemoveItem()
{
}
void HashTable::PrintTable()
{
for (int i = 0; i < table->size; i++)
{
std::cout << table[i].name; // Right here I get an error that says: class "std::vector<cell, std::allocator<cell>>" has no member "name".
}
}
int main()
{
HashTable theTable(5);
theTable.AddItem("Ryan", 27, "Sword");
theTable.AddItem("Melony", 24, "Axe");
theTable.PrintTable();
}

Vector member always zero size on call to member function that uses push_back to add to the vector member

What I am trying to do is add cards to a vector that is to be a Blackjack hand, but each time I enter the function that uses push_back to add a card to the vector, the vector starts out empty. The problem is in my Hand class in the addCardToHand function, and the same issue is present in the same class in my showHand function. I have whittled the code down as much as I could but still present a full working version with the issue. I cannot figure out why my Hand class treats the hand as brand new every time I call a function in the class. Please advise.
// Card.h
#ifndef CARD_H
#define CARD_H
#include <string>
#include <array>
class Card {
private:
int rank;
int suit;
int hardValue;
int softValue;
static const std::array<std::string,14> ranks;
static const std::array<std::string,5> suits;
public:
Card();
Card(int rank, int suit);
int getHardValue() const;
int getSoftValue() const;
std::string toString() const;
};
#endif
// Card.cpp
#include "Card.h"
const std::array<std::string,14> Card::ranks {"","A","2","3","4","5","6","7","8","9","10","J","Q","K"};
const std::array<std::string,5> Card::suits {"","C","D","H","S"};
Card::Card() : rank(0), suit(0) {
hardValue = 0;
softValue = 0;
}
Card::Card(int rank, int suit) : rank(rank), suit(suit) {
if (rank == 1) {
hardValue = 1;
softValue = 11;
}
else if (rank <= 10) {
hardValue = rank;
softValue = rank;
}
else {
hardValue = 10;
softValue = 10;
}
}
int Card::getHardValue() const {
return hardValue;
}
int Card::getSoftValue() const {
return softValue;
}
std::string Card::toString() const {
return ranks[rank] + suits[suit];
}
// Shoe.h
#ifndef SHOE_H
#define SHOE_H
#include <vector>
#include <random>
#include "Card.h"
class Shoe {
private:
int numDecksInShoe;
std::vector<Card> shoe;
static int currentCard;
static int maxDealCard;
static const unsigned long int seed;
static std::mt19937 randEng;
void renewShoe();
public:
Shoe();
explicit Shoe(int numDecksInShoe);
std::vector<Card> getShoe() const;
int getCurrentCard() const;
int getMaxDealCard() const;
void shuffle();
Card dealCard();
};
#endif
// Shoe.cpp
#include <ctime>
#include "Shoe.h"
const unsigned long int Shoe::seed = static_cast<unsigned long int>(std::time(nullptr));
std::mt19937 Shoe::randEng(seed);
int Shoe::currentCard = 0;
int Shoe::maxDealCard = 51;
Shoe::Shoe() {
}
Shoe::Shoe(int decksInShoe) {
numDecksInShoe = decksInShoe;
int count = 0;
for (int i = 0; i < numDecksInShoe; i++) {
for (int suit = 4; suit >= 1; suit--) {
for (int rank = 1; rank <= 13; rank++) {
Card card(rank,suit);
shoe.push_back(card);
count += 1;
}
}
}
currentCard = 0;
maxDealCard = count - 1;
}
std::vector<Card> Shoe::getShoe() const {
return shoe;
}
int Shoe::getCurrentCard() const {
return currentCard;
}
int Shoe::getMaxDealCard() const {
return maxDealCard;
}
void Shoe::shuffle() {
Card temp;
std::uniform_int_distribution<int> deckDist(0,numDecksInShoe*52-1);
int index;
for (int i = 0; i < numDecksInShoe*52; i++) {
do {
index = deckDist(randEng);
} while (index == i);
temp = shoe[index];
shoe[index] = shoe[i];
shoe[i] = temp;
}
std::uniform_int_distribution<int> maxDeal(10,41);
int tempMax = (numDecksInShoe-1)*52 - 1;
maxDealCard = tempMax + 51 - maxDeal(randEng);
}
Card Shoe::dealCard() {
if (currentCard == maxDealCard) {
renewShoe();
}
Card dealCard = shoe[currentCard];
currentCard += 1;
return dealCard;
}
void Shoe::renewShoe() {
Shoe newShoe(numDecksInShoe);
shoe = newShoe.getShoe();
shuffle();
}
here is my Hand class
// Hand.h
#ifndef HAND_H
#define HAND_H
#include <vector>
#include <string>
#include "Card.h"
class Hand {
private:
std::vector<Card> hand;
public:
Hand();
std::vector<Card> getHand() const;
void addCardToHand(Card card);
void clearHand();
Card revealBottomCard();
std::string showHand() const;
std::string peakHand() const;
};
#endif
// Hand.cpp
#include <iostream>
#include "Hand.h"
Hand::Hand() {
}
std::vector<Card> Hand::getHand() const {
return hand;
}
void Hand::addCardToHand(Card card) {
std::cout << card.toString() << std::endl;
hand.push_back(card);
}
void Hand::clearHand() {
hand.clear();
}
std::string Hand::showHand() const {
std::string returnString = "";
for (int i = hand.size()-1; i >= 1; i--) {
returnString += hand[i].toString() + "\n";
}
returnString += "XX\n";
return returnString;
}
std::string Hand::peakHand() const {
std::string returnString = "";
for (int i = hand.size()-1; i >= 0; i--) {
returnString += hand[i].toString() + "\n";
}
return returnString;
}
here is the Table class that has the code that calls the Hand class functions
// Table.h
#ifndef TABLE_H
#define TABLE_H
#include "Shoe.h"
#include "Player.h"
class Table {
private:
Shoe shoe;
public:
explicit Table(Shoe shoe);
Shoe getShoe() const;
void clearHand(std::vector<Player> players);
void dealHand(std::vector<Player> players);
};
#endif
// Table.cpp
#include <iostream>
#include "Table.h"
Table::Table(Shoe shoe) : shoe(shoe) {
}
Shoe Table::getShoe() const {
return shoe;
}
void Table::clearHand(std::vector<Player> players) {
for (Player &player : players) {
player.getHand().clearHand();
}
}
void Table::dealHand(std::vector<Player> players) {
for (int i = 0; i <= 1; i++) {
for (Player &player : players) {
player.getHand().addCardToHand(shoe.dealCard());
}
}
}
// Player.h
#ifndef PLAYER_H
#define PLAYER_H
#include "Hand.h"
class Player {
private:
std::string name;
Hand hand;
double money;
public:
explicit Player(std::string name, double money = 1000.0);
std::string getName() const;
Hand getHand() const;
double getMoney() const;
};
#endif
// Player.cpp
#include "Player.h"
Player::Player(std::string name, double money) : name(name), money(money) {
}
std::string Player::getName() const {
return name;
}
Hand Player::getHand() const {
return hand;
}
double Player::getMoney() const {
return money;
}
and finally here is a short driver that runs and displays the issue
// blackjack testing
#include <iostream>
#include "Player.h"
#include "Table.h"
int main() {
std::vector<Player> players {Player("Tom",1500.0),Player("Sue"),Player("Dave")};
Shoe shoe1(6);
Table table1(shoe1);
table1.dealHand(players);
for (Player player : players) {
std::cout << player.getName() << "'s hand\n";
std::cout << player.getHand().showHand() << "\n\n";
}
}
The output is below. I printed out the cards that were added to the hand vector (and then 'forgotten') and below that above the XX's, if everything were to work correctly you should see the 4, 5 and 6 of spades since I did not shuffle the deck. The XX's are to simulate face down bottom card.
AS
2S
3S
4S
5S
6S
Tom's hand
XX
Sue's hand
XX
Dave's hand
XX
Sorry for dumping all this code in here, but I wanted to provide a full working solution and this is as small as I could get it. Thanks for any help.
player.getHand().addCardToHand(...);
player.getHand() returns a temporary Hand object that's a copy of player.hand. Then you add a card to that temporary object. Then that temporary object dies, added card and all. player.hand remains unchanged. This line of code is an elaborate no-op.
To add on #Igor's answer, the best way to fix this should probably return a reference instead:
const Hand& Player::getHand() const {
return hand;
}
I made this a const because returning a non-const could (potentially) allow you to break constness of a constant Player object. That is just inviting potential bugs.
Because of this, you may want to add a non-const version too:
Hand& Player::getHand() {
return hand;
}
Now you can't modify a const Player object, yet modify it properly when you need to.

C++ - Segmentation fault when returning a string

I have this class
#include "Room.h"
#include "Book.h"
#include <cstdlib>
#include <iostream>
static int book_counter = 100;
//Constructors
Book::Book() {
for(int i = 0; i < 13; i++) {
this->customer_name += 97 + rand() % 26;
}
this->arrival = rand() % 30;
this->duration = 1 + (rand() % 10);
this->ppl = 1 + rand() % 5;
this->room = nullptr;
this->book_code = book_counter++;
}
Book::Book(std::string nm, int arr, int dur, int ppl) {
this->customer_name = nm;
this->arrival = arr;
this->duration = dur;
this->ppl = ppl;
this->room = nullptr;
this->book_code = book_counter++;
}
//Methods
int Book::getArr() {
return arrival;
}
int Book::getDur() {
return duration;
}
int Book::getPpl() {
return ppl;
}
void Book::anathesi(Room* x) {
this->room = x;
}
int Book::getBookCode() {
return book_code;
}
Room* Book::getRoom() {
return room;
}
std::string Book::getCustomerName() {
return customer_name;
}
which includes a string getter method getCustomerName().
When I call this method on main, via an instance created via the first constructor, everything works fine. On the other hand, if the instance is created via the second constructor, the method will cause a segmentation fault.
It seems like customer_name has an infinite length, thus causing a segmentation fault when I try to return it.
The method is called in main with this line of code:
cout << hotel.getBooks(i)->getBookCode() << " " << hotel.getBooks(i)->getCustomerName()
<< " " << hotel.getBooks(i)->getRoom()->getRoomCode() << "\n";
I am new into C++, so please elaborate my fault as much as needed.
The header file for class Book:
#ifndef PROJECT_BOOK_H
#define PROJECT_BOOK_H
#include <string>
class Room;
class Book {
protected:
std::string customer_name;
int book_code;
int arrival;
int duration;
int ppl;
Room* room;
public:
Book();
Book(std::string nm, int arr, int dur, int ppl);
void anathesi(Room* x);
int getArr();
int getDur();
int getPpl();
int getBookCode();
std::string getCustomerName();
Room* getRoom();
};
#endif //PROJECT_BOOK_H
In Hotel.h:
private: std::vector<Book*> books;
public: Book* getBooks(int i);
In Hotel.cpp:
Book* Hotel::getBooks(int i) {
return books[i];
}
Found the problem and fixed it.
I was creating instances with this piece of code:
Book obj(onoma, afiksh - 1, meres, arithmos);
which caused the segmentation I said.
I changed this to:
Book *obj = new Book(onoma, afiksh - 1, meres, arithmos);
and fixed the problem. Thanks for your time and help.
Unfortunately, I don't really know why this works, but it does, everything functions properly. Therefore I guess I'll have to look at new documentation.