Why pointer to pointer was used in the code? - c++

Why pointer to pointer has been used rather than single pointer in the code? Also do you think the destructor was written wrong if it is how can i make it correct?
pointer to pointer: employee** _arr;
You can see the code below:
#include<iostream>
class employee {
private:
std::string _name;
std::string _surname;
int _year;
double _salary;
static int numberOfEmployees;
public:
employee() {
_name = "not-set";
_surname = "not-set";
_year = 0;
_salary = 0;
numberOfEmployees++;
}
employee(int year, std::string name, std::string surname) {
_name = name;
_surname = surname;
_year = year;
numberOfEmployees++;
calculateSalary();
}
void calculateSalary() {
//salary = 2310 + 2310 * year * 12/100.0
_salary = 2310 + (2310 * (double)_year) * (12 / 100.0);
}
void printInfo() {
std::cout << _name << " " << _surname << " " << _year << " " << " " << _salary << " TL/month" << std::endl;
}
static int getEmployeeCount() {
return numberOfEmployees;
}
};
class employeeList {
private:
int _size;
int _lenght;
employee** _arr;
public:
employeeList() :_size(1), _lenght(0), _arr(NULL) {}
employeeList(int size) :_size(size) {
_arr = new employee * [_size];
_lenght = 0;
}
int listLength() {
return _lenght;
}
employee retrieve_employeeFromIndex(int index) {
if (index >= 0 && index < _size) {
return *_arr[index];
}
}
void addToList(employee* item) {
_lenght++;
if (_lenght <= _size) {
_arr[_lenght - 1] = item;
}
else {
std::cout << "you cannot add another employee!";
}
}
static void printEmployees(employeeList el) {
for (int i = 0; i < el._lenght; i++) {
el._arr[i]->printInfo();
}
}
~employeeList() {
delete[] _arr;
}
};
int employee::numberOfEmployees = 0;
int main() {
employee a;
employee b(5, "John", " Doe");
employee c(3, "Sue", "Doe");
employeeList empList(employee::getEmployeeCount());
empList.addToList(&a);
empList.addToList(&b);
empList.addToList(&c);
employeeList::printEmployees(empList);
std::cout << empList.listLength() << std::endl;
return 0;
}
you can see the output:
Why pointer to pointer has been used rather than single pointer in the code? Also do you think the destructor was written wrong if it is how can i make it correct?

Why pointer to pointer was used in the code?
This is known only by the author who wrote the code. We can make a reasonable guess that their intention may have been to:
Allocate a dynamic array of objects, using a bare pointer to the first element of that array.
Indirectly point to objects stored elsewhere, hence they wanted to use an array of pointers, thus a pointer to first element of the array is a pointer to a pointer.
Their choice 1. to use an owning bare pointer is unnecessary, and there are better choices available which do not require an owning bare pointer. Most commonly, std::vector would be used to create a dynamic array.
Their choice 2. to indirectly point to objects that aren't owned by the class instance is not quite as safe as having the class instance own the objects, but regardless that may have been a reasonable choice depending on the reasons they chose this design. It is impossible to tell whether the choice was good without documentation of what the program is supposed to do. Based on the generic name of the class, I suspect that it wasn't a good choice.
do you think the destructor was written wrong
It can be considered correct. There are other issues with the class though.
The entire employeeList class seems pointless, and can easily be replaced by a std::vector. printEmployees is the only member function that wouldn't be directly provided by a vector. You can use a non-member function for that instead.

Im not expert but u will bumb your topic :P
I think that question is not precised. You mean that pointer to pointer:?
employee** _arr;
Because is pointing a pointer:
_arr = new employee * [_size];
I think that it have sense because array is a pointer? I can be wrong ofcourse coz I just started do educate.
Why do you think destruktor is wrong? It's deleting a pointer.

Related

Passing an Array of Objects into a Function

I have a class that defines object.name as "Ben" and object.favNum as 25.
I also have an array (names) to store 5 objects of this class.
Before I output the attributes of the objects in the array, I change the value of names[0].name to "Jim" and names[0].favNum to 40, using pointer notation.
Here is my code:
#include<iostream>
class Person {
public:
std::string name = "Ben";
int favNum = 25;
};
int main()
{
Person names[5];
Person *ptr = &names[0];
// Changing Values
(ptr + 0)->name = "Jim";
(ptr + 0)->favNum = 40;
for (int i = 0; i < 5; i++)
{
std::cout << (std::string) (ptr + i)->name << std::endl;
std::cout << (int) (ptr + i)->favNum << std::endl << std::endl;
}
system("pause>0");
}
Output:
Jim
40
Ben
25
Ben
25
Ben
25
Ben
25
Where I have the "Changing Values" comment, I want to replace those 2 lines with a function.
The function will be able to change the values as I am doing with the 2 lines.
This is where I am having a problem.
I'm struggling with figuring out what type to declare the function as, how to pass the pointer in, how to receive the pointer, and how to change the values of the objects in the array in the function.
I would recommend against the use of pointers, unless you really need pointers.
// use references instead
void change(Person &person) {
person.name = "Jim";
person.favNum = 40;
};
int main()
{
Person names[5];
change(names[0]);
// ...
}
The appropriate way to write such a function would be using references. A reference is similar to a pointer, but can never be nullptr. In your case you don't need nullability, you just need to edit a Person without copying it.
You probably want change() to be parametric though:
// use references instead
void change(Person &person, std::string name, int favNum) {
person.name = std::move(name);
person.favNum = favNum;
}
But now you are assigning all members of Person using this function, which makes it pointless. It would be simpler if you assigned Person. Why not use a struct and aggregate initialization:
struct Person {
std::string name = "Ben";
int favNum = 25;
};
int main()
{
Person names[5];
names[0] = {"Jim", 40};
// ...
}
On a side note, what you are doing here is unnecessary complicated:
(ptr + 0)->name = "Jim";
// this is equivalent to
ptr[0].name = "Jim";
// this is equivalent to
ptr->name = "Jim";
This is how your code should look in "real" c++ (the setting of the values will be done in the constructor function or using the setNameAndFavNum() function):
#include <array>
#include <iostream>
struct Person {
public:
Person(const std::string& name_ = "Ben", int favNum_ = 25) : name(name_), favNum(favNum_) {};
void setNameAndFavNum(const std::string& name_, int favNum_) {
name = name_;
favNum = favNum_;
};
std::string name;
int favNum;
};
int main() {
std::array<Person, 5> names;
// Changing Values
names[0].setNameAndFavNum("Jim", 40);
// Alternatively you can use the constructor and implicit copy constructor
// names[0] = {"Jim", 40};
for (int i = 0; i < names.size(); i++) {
std::cout << names[i].name << std::endl;
std::cout << names[i].favNum << std::endl << std::endl;
}
}
You shouldn't mess around with pointers and raw values when writing c++ code.

Through what to call the method, if I already created constructor with initialization of array of structures?

I'm trying to call the method displayChoices, member of the class MachineManager through the object of the class. But I already have a constructor with initializing of the array of structures. How I understood when we create an object of the class compiler implicitly create a default constructor of the class.
Question: How to call method displayChoices?
#include "MachineManager.h"
using namespace std;
int main()
{
MachineManager mjp;
mjp.displayChoices();
return 0;
}
struct BrewInfo {
string* DrinkName;
double* Cost;
int* Number;
};
class MachineManager {
static const int Num_Drinks = 3; /// why it works only with static?!!!
BrewInfo* BrewArr[Num_Drinks];
public:
MachineManager()
{
*BrewArr[0]->Cost = 1.25;
*BrewArr[0]->Number = 20;
*BrewArr[1]->DrinkName = "pepsi";
*BrewArr[1]->Cost = 1.15;
*BrewArr[1]->Number = 17;
*BrewArr[2]->DrinkName = "Aloe";
*BrewArr[2]->Cost = 2.00;
*BrewArr[2]->Number = 15;
};
int displayChoices();
}
int MachineManager::displayChoices() // (which displays a menu of drink names and prices)
{
cout << 1;
int choice;
cout << "|1." << *BrewArr[0]->DrinkName << " |2." << *BrewArr[1]->DrinkName << " |3." << *BrewArr[2]->DrinkName << " |" << endl;
cin >> choice;
if (!choice || choice == 0) {
system("slc");
displayChoices();
}
else
return choice;
}
displayChoices has to print a menu in console.
You have a majo bug in your source code. You do not yet understand, how pointer work.
You are defining an array of pointer with BrewInfo* BrewArr[Num_Drinks];.
But these pointers are not initialized. They point to somewhere. Then you are dereferencing those pointers (pointing to somewhere) and assigning a value to somewhere in the memory.
This is a major bug.
The array dimensions for C-Sytle arrays must be a compile time constant.
You cannot write
int x=3;
unt array[x];
This is C99 code (called VLA, Variable length array), but not C++.
Solution for you problem:
Do never use C-Style arrays, like int array[5]. Use STL container like std::vector instead.
Do not use pointers.
This is your major problem. Define your array with BrewInfo BrewArr[Num_Drinks];. Please remove also the pointer from
struct BrewInfo {
string* DrinkName;
double* Cost;
int* Number;
};

How do you delete both a pointer in a vector of pointers of Objects and the Object itself?

I'm trying to code an text-based adventure game builder. I have three classes: Room, Object, and my main class. In my Room class, I have a (private) vector of pointers of Objects: vector<Object*> objectsInRoom
This keeps track of all the Objects stored in each room. I have a function called objects() in the Room class that returns objectsInRooms for when I call that vector in my main class.
vector<Object*> Room::objects() { return objectsInRoom; }
In my main class, in my function pickUpObject(), I've created a vector of pointers of Objects called roomObject. I call objects() in the Room class and store the Objects in objectsInRoom (which is only accessed in the Room class) in roomObject (which is accessible in my function in main). I also have a vector of Objects called allObjects that stores all the items that I want to pick up from the room and carry around with me. It has a global scope.
I want to make it so that if I pick up an item in a particular room, I add the item to allObjects, delete the pointer to that element in roomObjects (and thus the pointer to that element in objectsInRooms in the Room class), and the item itself.
My pickUpObject function is: (Room* current just tells me what room I'm in and thus what Objects I have)
void pickUpObject(vector<Object>&allObjects, Room* current)
{
vector<Object*>roomObjects; int length; string name; char flag;
roomObjects = current->objects();
length = roomObjects.size();
bool repeat = true;
while (repeat)
{
if (length == 0)
{
cout << "There are no objects to pick up in " << current->name() << endl;
repeat = false;
}
else
{
cout << "There is a ";
for (int k = 0; k < roomObjects.size() - 1; k++)
{
cout << roomObjects[k]->getName();
if (length > 2)
cout << ", ";
}
if (length > 1)
cout << " and " << roomObjects[length - 1]->getName() << " here." << endl;
else
cout << roomObjects[length-1]->getName() << "." << endl;
cout << "What object do you want to pick up?" << endl;
cin >> name;
//this is where the deletion happens
for (int i = 0; i < length; i++)
if (name.compare(roomObjects[i]->getName()) == 0)
{
allObjects.push_back(*roomObjects[i]);
roomObjects.erase(roomObjects.begin() + i);
deleteVectorContent(roomObjects, i, i + 1);
}
cout << "roomObject size = " << roomObjects.size() << endl;
cout << "--------------------" << endl;
cout << "allObject size = " << allObjects.size() << endl;
for (int i = 0; i < allObjects.size(); i++)
cout << allObjects[i].getName() << endl;
for (int i = 0; i < roomObjects.size(); i++)
{
cout << roomObjects[i]->getName() << endl;
}
cout << "Do you want to pick up another object? (Y/N): ";
cin >> flag;
if (flag == 'N')
repeat = false;
}
}
}
I've looked up various posts on StackOverflow to try and resolve my dilemma. In main, I've created a method called deleteVectorContent to try and delete the pointer.
void deleteVectorContent(vector<Object*> objectVector, int start, int stop)
{
for (int k = start; k < stop; k++)
delete objectVector[k];
objectVector.clear();
}
I've also tried 'roomObjects.remove()' to remove the item itself from that room. Whenever I compile, however, my compiler also throws me an exception. Help would be greatly appreciated.
P.S. The link to this assignment is here. If you scroll down to the "Extra Credit for the Programming Assignment" and go to the first one marked "10 points," that is what I am working on. Thank you so much for the help!
Room::objects() is returning a copy of objectsInRoom, so any modifications that pickUpObject() makes to that returned vector will not be applied back to objectsInRoom. You would need to make Room::objects() return a reference to objectsInRoom instead, eg:
vector<Object*>& Room::objects()
{
return objectsInRoom;
}
void pickUpObject(vector<Object> &allObjects, Room* current)
{
vector<Object*> &roomObjects = current->objects();
...
}
Otherwise, don't provide direct access to objectsInRoom at all. Introduce new methods to Room to access/remove a given Object* from its objectsInRoom, eg:
int Room::numObjects()
{
return objectsInRoom.size();
}
Object* Room::getObject(int index)
{
return objectsInRoom[index];
}
Object* Room::takeObject(int index)
{
Object *obj = objectsInRoom[index];
objectsInRoom.erase(objectsInRoom.begin()+index);
return obj;
}
void pickUpObject(vector<Object> &allObjects, Room* current)
{
int length = current->numObjects();
...
for (int i = 0; i < length; ++i)
{
if (name == current->getObject(i)->getName())
{
Object *obj = current->takeObject(i);
allObjects.push_back(*obj);
delete obj;
break;
}
}
...
}
Note that allObjects is receiving copies of the actual Objects, not Object* pointers. The code you showed is leaking memory when you make a copy of *roomObjects[i] and then erase() the Object* at i without delete'ing the Object it is pointing at. If Object is so easily copyable, you can save yourself a lot of headaches by simply getting rid of all the Object* pointers and just use Object everywhere:
class Room
{
vector<Object> objectsInRoom;
...
};
int Room::numObjects()
{
return objectsInRoom.size();
}
Object& Room::getObject(int index)
{
return objectsInRoom[index];
}
Object Room::takeObject(int index)
{
Object obj = objectsInRoom[index];
objectsInRoom.erase(objectsInRoom.begin()+index);
return obj;
}
void pickUpObject(vector<Object> &allObjects, Room* current)
{
int length = current->numObjects();
...
for (int i = 0; i < length; ++i)
{
if (name == current->getObject(i)->getName())
{
allObjects.push_back(current->takeObject(i));
break;
}
}
....
}
Otherwise, don't mix Object with Object* like you are, use Object* everywhere.
If you have a fixed set of Objects for the game, I would create a global vector<Object> to hold them all, and then just pass around Object* pointers everywhere as needed. Then you don't have to worry about cleaning up memory manually at all:
vector<Object> allGameObjects;
// fill as needed...
void Room::addObject(Object *obj)
{
objectsInRoom.push_back(obj);
}
Object* Room::takeObject(int index)
{
Object *obj = objectsInRoom[index];
objectsInRoom.erase(objectsInRoom.begin()+index);
return obj;
}
void pickUpObject(vector<Object*> &allObjects, Room* current)
{
...
allObjects.push_back(current->takeObject(i));
...
}
If you absolutely need a vector that owns Object* pointers that have to be cleaned up before the vector is destroyed, consider using vector<unique_ptr<Object>> for that, let the compiler and STL handle the hard work for you. If you ever find yourself having to write something like deleteVectorContent(), rethink your design.

Changing a private value of a class in method not returning the changes to main()

I'm having a problem that I haven't found an answer for in a week now. I have a dynamic array class and it has a method to add string values to it. It's supposed to represent an inventory you can add items to. However, I find that the changes made in the method to the private values of the class element aren't "updated" when I try to call for a print-method for the class element "backpack" later in the main(). I think this might be a problem due to referencing issues, but I've seen this work when a class hasn't been in a different module.
My "backpack" module print and add methods:
const int INITIAL_SIZE = 5;
Inventory::Inventory():
array_(new string[INITIAL_SIZE]),
max_space_(INITIAL_SIZE),
used_space_(0) {}
void Inventory::add(string item){
if ( size() == max_space_ ) {
string* new_array = new string[2 * max_space_];
for ( int i = 0; i < size(); ++i ) {
new_array[i] = array_[i];
}
delete [] array_;
array_ = new_array;
max_space_ = 2 * max_space_;
}
array_[used_space_] = item;
++used_space_;
}
void Inventory::print() {
for ( int i = 0; i < size(); ++i ) {
cout << array_[i] << endl;
}
}
The main():
Inventory inv;
string input;
while (cout << "input> "
and getline(cin,input)){
add_to_bag(input,inv);
So the point is you reset the inventory when you give it new contents. The function add_to_bag(); is:
void add_to_bag(string input, Inventory inv){
const string WHITESPACE1_REGEX = "[[:space:]]*";
const string WHITESPACE2_REGEX = "[[:space:]]+";
const string WORD_REGEX = "[[:alpha:]_]+";
const string LINE_REGEX =
WHITESPACE1_REGEX +
WORD_REGEX +
"(" +
WHITESPACE2_REGEX +
WORD_REGEX +
")*" +
WHITESPACE1_REGEX;
regex line_reg(LINE_REGEX);
regex word_regex(WORD_REGEX);
string line = input;
if ( regex_match(line, line_reg) ) {
sregex_iterator iter(line.begin(), line.end(), word_regex);
sregex_iterator end;
while ( iter != end ) {
inv.add(iter->str());
++iter;
}
} else {
cout << "Error: unknown inventory contents." << endl;
}
}
Your problem is:
void add_to_bag(string input, Inventory inv);
You pass a copy of the Inventory object to add_to_bag. You modify that copy ... and then it gets thrown away. The fix is to pass by reference:
void add_to_bag(string input, Inventory &inv);
Incidentally, in real-life code, I would strongly advise the use of std::vector<std::string> rather than "roll your own". There are a number of tricky exception handling issues you have got wrong here - and unless Inventory doesn't have a destructor (implying a memory leak), or does have a correct copy constructor I would have expected you to run into "double free" issues. (Read about "The Rule of Three".)
A simple way to design your class would be as follows:
class Inventory {
private:
std::vector<std::string> items_;
public:
Inventory(){}
~Inventory(){}
void addItem( const std::string& item ) {
items_.push_back( item );
}
void printInventory() const {
int idx = 0;
for (; idx < items_.size(); ++idx ) {
std::cout << items_[idx] << std::endl;
}
}
void clearInventory() {
items_.clear();
}
};
And as for your problem Martin Bonner had already answered it with the modifying of the copy and the removal of it afterwards and the other issues with the memory management.

Casting objects in vector in c++

I know this question has already been asked, but none of the answers that I have as of yet found seem to suffice. I am creating a vector of pointers to a base class and adding all sorts of derived classes to it. Now, the base class has a virtual function that is overridden in all of the derived classes and that is unique to each of them. So, when I go through the vector and retrieve those objects and call the function on that object, I need it to call the right one, but all it will do is call the base class version. I am even trying to cast the individual elements back to their original class when I retrieve them from the vector but they refuse to be cast! e.g.
vector<base*> myBase;
DerivedClass *myDerived = static_cast<DerivedClass> myBase[i];
This doesn't work, despite the fact that everything I've read suggests that it should. My debugger says that despite all of this, myDerived is still of type base and it's version of my virtual function is being called.
Any ideas?
class BankAccount {
public:
BankAccount(string namein, string typein){
name = namein;
type = typein;
balance = 0;
}
virtual string getType();
virtual void printTransactions() = 0;
virtual int withdraw(double amt){
return getBalance() -amt;
}
};
class SavingsAccount: public BankAccount {
public:
SavingsAccount(string namein, string typein);
void addTransaction(string transType, string name);
virtual int withdraw(double amt);
void printTransactions();
virtual string getType();
private:
};
SavingsAccount::SavingsAccount(string namein, string typein): BankAccount(namein, typein) {
}
int SavingsAccount::withdraw(double amt){
double aBal = getBalance() - amt;
if (aBal > 0){
setBalance(aBal);
}
return getBalance() - amt;
}
class CheckingAccount: public SavingsAccount {
public:
CheckingAccount(string nameIn, string typein): SavingsAccount(nameIn, typein){
}
virtual int withdraw(double amt);
void printTransactions();
string getType(){
return "Checking";
}
};
int CheckingAccount::withdraw(double amtIn){
double newBal = getBalance() - amtIn;
if (newBal < 500.00 && newBal > 2.49) {
setBalance(newBal - 2.50);
}
return newBal;
}
int main(int argc, const char * argv[])
{
vector<BankAccount*> myAccts;
SavingsAccount *mySav;
CD *myCD;
CheckingAccount *myCheck;
switch (option) {
case 1: {
string name;
string type;
cout << "Enter name: ";
cin >> name;
getline(cin, dump);
cout << "Enter account type: ";
cin >> type;
getline(cin, dump);
if (type.compare("Checking") == 0) {
CheckingAccount myCheck1 = CheckingAccount(name, type);
myAccts.push_back(&myCheck1);
}
case 3:{
for (int x = 0; x < myAccts.size(); x++) {
if (myAccts[x]->getName() == name && myAccts[x]->getType() == type) {
if (type == "Savings") {
mySav = static_cast<SavingsAccount*>(myAccts[x]);
double y = mySav->withdraw(amt);
if (y < 0){
cout << "Insufficient funds!";
}
}
if (type == "Checking") {
myCheck = myAccts[x]->GetDerived();
double y = myCheck->withdraw(amt);
if (y < 0){
cout << "Insufficient funds!";
}
if (y < 497.5) {
cout << "Withdrawal fee: $ 2.50" << endl;
}
}
}
Checking Account is a child of Savings Account. Sorry.
Your concept is correct and shouldn't require any casting. The whole point of virtual functions is that if you're holding a base class pointer or reference and call a virtual function, the most derived version of this function will be called at runtime.
The error I see is this:
if (type.compare("Checking") == 0) {
CheckingAccount myCheck1 = CheckingAccount(name, type);
myAccts.push_back(&myCheck1);
You are creating a checking account on the stack, then taking it's address and pushing that address into the vector. At the end of the if block myCheck1 will go out of scope and be destroyed. Your vector will have an address to a location in the stack and you will have Undefined Behavior.
Instead do:
if (type.compare("Checking") == 0) {
myAccts.push_back(new CheckingAccount(name, type));
And similar for the other types. Get rid of all of those casts. In this version you will have to delete all of the items in the vector at the end. If you use a std::vector<std::unique_ptr<BankAccount>> then the unique_ptr will take care of cleaning up your allocated objects.
You need to use new to create your accounts... you have:
if (...)
{
CheckingAccount myCheck1 = CheckingAccount(name, type);
myAccts.push_back(&myCheck1);
}
...myCheck1 gets destroyed when leaving that if scope, leaving myAccts with a pointer to an effectively random location on the stack that has undefined behaviour if accessed. Change to:
if (type == "Checking")
myAccts.push_back(new CheckingAccount(name, type));
You will then need to have matching deletes for the vector elements. Googling "C++ new delete tutorial" would be a good idea. The next stage is to learn how to use smart pointers, for example - std::shared_pointer - which remove the burden of remembering to delete.
"Case 3" can be corrected/simplified to:
for (int x = 0; x < myAccts.size(); x++)
if (myAccts[x]->getName() == name && myAccts[x]->getType() == type) {
double y = myAccts[x]->withdraw(amt);
if (y < 0)
cout << "Insufficient funds!";
if (type == "Checking" && y < 497.5)
cout << "Withdrawal fee: $ 2.50" << endl;
}
Notice in particular the double y = myAccts[x]->withdraw(amt); - the virtual function makes sure the right version is called without you having to do anything type-specific in the calling code.
Have you tried something like this?
class base
{
public:
inline DerivedClass *GetDerived() {return (DerivedClass*)this;}
...
};
DerivedClass *myDerived = myBase[i]->GetDerived();