Creating List Like Array with Dynamic Memory Management - c++

There are a lecture class and student class. We are trying to save student information on lecture class with arrays.
For example:
Student * studentList = new Student[numberOfStudent];
studentAdd("Mary");
studentDelete("Mary");
Problem:
User is not giving number of student and number of student is increasing when user add a new one with a one of lecture method. So I think that i need a list like structer to save them but it is forbidden for this work. Do you have any efficient ideas than my temporary solution?
My temporary solution:
Saving number of student and array size and when number of student is more than size copy array to a new one which is bigger than old one.
This question is related to my assigment which we are forcing to this by
*using dynamically allocated memory using pointers
*without using any static arrays with fixed sizes or other data structures such as
vector from the standard library

you could just use functions if you don't want to use objects. Note that I haven't compiled this code.
#include <iostream>
#include <sstream>
#include <string>
#include "Student.h"
void add(Student **list, Student *rhs);
void destroy(Student **list,int const &idx);
void destroy(Student **list,const char* student_name); //find the student name and delete
void resize(Student **list,int const &idx);
Student** begin(Student **list,); //get the first Student
Student** end(Student **list,); //the end of the array
void clear(Student **list,); //drop all Students
int main(int argc, char **argv)
{
if(argc < 2)
{
stc::cerr << "not enough parameters" << std::endl;
}
istringstream buffer(argv[1]);
int value;
buffer >> value;
Student ** studentList = new *Student[value];
int s
add(studentList, "Mary");
destroy(studentList, "Mary");
return(0);
}
void add(Student **list, Student *rhs) { /*definition*/ }
void destroy(Student **list, int const &idx) { /*definition*/ }
void destroy(Student **list, const char* student_name) { /*definition*/ }
void resize(Student **list, int const &idx) { /*definition*/ }
Student** begin(Student **list) { /*definition*/ }
Student** end(Student **list) { /*definition*/ }
void clear(Student **list) { /*definition*/ }
Now just define all that and you are all set
I do not recommend this approach
I would use objects... and taking into account what PaulMcKenzie said about capacity
class StudentList
{
private:
Student **list;
std::size_t size;
std::size_t capacity;
public:
StudentList(){}
~StudentList(){ this->clear(); }
inline void add(Student *rhs) { //definition }
inline void destroy(int const &idx) { //definition }
inline void destroy(const char* student_name) { //definition }
inline void resize(int const &idx) { //definition }
inline Student** begin() { //definition }
inline Student** end() { //definition }
inline void clear() { //definition }
};
And if possible
Iterators
Underneath vector you will find a similar implementation, it uses Iterators to encapsulate the Student**.

Related

Private vector in class

class MyStrValArray
{
private:
vector<char> p;
public:
void init(const int n);
void clear();
unsigned capacity();
unsigned size();
};
I want to have a vector as private class member, and in the public part, I want to declare the size(const int n) of the vector. Is there a way to do this?
And the reason I want to use vector is, I need to get the size / capacity of the memory, resize, or remove the nth element of the memory. Is it right to use vector in this case?
If you are trying to implement custom string implementation then ,having "char * data" is more appropriate.
Otherwise you can use vector like this :
#include <iostream>
#include <vector>
using namespace std;
class MyStrValArray
{
private:
vector<char> p;
public:
MyStrValArray() {}
MyStrValArray(const int sz ) : p(sz){}
void init(const int n)
{
p.resize(n);
}
void clear()
{
p.clear();
}
unsigned capacity()
{
return p.capacity();
}
unsigned size()
{
return p.size();
}
};
int main()
{
MyStrValArray ma;
ma.init(4);
std::cout<<ma.size()<<std::endl;
return 0;
}

Sorting vector objects with accessor

This is part of a C++ program based on the Alternative Vote electoral method, using VS2015. I have a class for Party
#pragma once
#ifndef _PARTY_H
#define _PARTY_H
#include <string>
class Party {
public:
Party();
~Party();
Party(std::string n, int pos);
void reset();
void upTotal();
int getPosition();
std::string getName();
int getVotes();
private:
std::string name;
int votes;
int position;
};
#endif
and
#include <iostream>
#include "Party.h"
using namespace std;
Party::Party() {}
Party::~Party() {}
Party::Party(string n, int p) {
name = n;
position = p;
}
void Party::reset() {
votes = 0;
}
void Party::upTotal() {
votes += 1;
}
int Party::getPosition() {
return position;
}
string Party::getName() {
return name;
};
int Party::getVotes() {
return votes;
}
I tried to sort on votes received using (calculated from ballot papers elsewhere in the program
void sortParties() {
sort(parties.begin(), parties.end(), [](const auto& a, const auto& b)
{
return a.getVotes() < b.getVotes();
});
}
which returned illegal operand errors. Moving the variables from private to public and writing the following did work
void sortParties() {
sort(parties.begin(), parties.end(), [](const auto& a, const auto& b)
{
return a.votes < b.votes;
});
}
which gets it working, but I want to write it with proper encapsulation using private variables and an accessor for votes. Do I need to overload somehow, or convert type?
You have the following functions defined:
int getPosition();
std::string getName();
int getVotes();
They should probably all be const; ie
int getPosition() const;
std::string getName() const;
int getVotes() const;
This will allow you to call the functions from your const object at
sort(parties.begin(), parties.end(), [](const auto& a, const auto& b)

dealing with dynamically allocated array of objects of a class in another class

I want the bag class to have an array of item objects that is dynamically allocated but not sure how to do this. Also need someone to have a look at the rest of my code. I want to add Item objects to a Bag object and perform operations on the thus formed ADT as is evident from the code.
Item.h
#ifndef ITEM_H
#define ITEM_H
class Item
{
char* item_name;
public:
Item(char *name);
void display_item(Item i);
~Item();
protected:
private:
};
#endif
Item.cpp
#include "Item.h"
#include<string.h>
#include<iostream>
#include<malloc.h>
using namespace std;
Item::Item(char* name)
{
item_name = new char[sizeof(name)];
strcpy(item_name,name);
}
void Item::display_item(Item i)
{
cout<<i.item_name<<" ";
}
Item::~Item()
{
}
Bag.h
#include "Item.h"
#ifndef BAG_H
#define BAG_H
class Bag
{
int no_of_items;
int capacity;
Item list[];
public:
Bag(int no_of_items);
void add(Item i);
void display();
~Bag();
protected:
private:
};
#endif
Bag.cpp
#include "Bag.h"
#include "Item.h"
#include<malloc.h>
Bag::Bag(int capacity)
{
Item list[capacity];
no_of_items =0;
}
void Bag::add(Item i)
{
if(no_of_items<capacity)
{
list[no_of_items] = i;
no_of_items++;
}
else
{
cout<<"bag is full";
}
}
void Bag:: display()
{
for(i=0;i<no_of_items;i++)
{
display_item(list[i]);
}
}
Bag::~Bag()
{
//dtor
}
I'll not speak on your code, if you have problems with it, ask in a separate question with minimal code to reproduce the error. Here is a link, at the end of this answer, explaining how to dynamically allocate memory for your array. If you are doing so because you need a variable sized array, I would recommend a vector. While an object of type array must have the size defined at compile time, a vector does not have this requirement, and you can use vector_pushback to add new elements with ease. But if you insist on using an array, follow the instructions here: http://www.cplusplus.com/forum/articles/416/
As possible, always use STL containers. They have analogous interface and are well documented. Most of them are dynamic. So, your code with STL containers (std::string and std::vector) could look like:
#include <string>
#include <vector>
#include <iostream>
class Item {
public:
Item(const std::string& name) : item_name(name) {}
virtual ~Item() {}
void display_item() {
std::cout << item_name << " ";
}
private:
std::string item_name;
};
class Bag {
public:
void add(const Item& i) {
items.push_back(i);
}
void display() {
for(std::vector<Item>::iterator it = items.begin();
it != items.end(); ++it)
it->display_item();
}
private:
std::vector<Item> items;
};
As your question is aiming on how to implement your example with dynamic allocation, the code above without STL containers can be done as:
#include <cstring>
#include <algorithm>
#include <iostream>
class Item {
public:
Item() : item_name(0) {} // required for new[] expression
Item(const char* name) : item_name(0) {
copyName(name);
}
virtual ~Item() {
delete[] item_name; // don't forget to free the allocated memory
}
void display_item() const {
std::cout << item_name << " ";
}
Item& operator=(const Item& other) { // required for copying
copyName(other.item_name);
return *this;
}
private:
void copyName(const char* str) {
// get the size of the new name and delete the actual name
const size_t name_size = strlen(str);
delete[] item_name;
// allocate memory for new name and copy it
item_name = new char[name_size + 1]; // extra place for '\0'
strcpy(item_name, str);
}
char* item_name;
};
class Bag {
public:
Bag(size_t cap = 0) :
items(cap ? new Item[cap] : 0), capacity(cap), size(0) {}
virtual ~Bag() {
delete[] items;
}
void add(const Item& i) {
// "resize" the actual array if there is no space for a new item
if(size == capacity) {
// allocate new array and copy the actual content
capacity += 100;
Item* temp = new Item[capacity];
std::copy(items, items + size, temp);
// delete the actual array and assign the newly allocated one
delete[] items;
items = temp;
temp = 0;
}
// add the new item
items[size] = i;
size++;
}
void display() {
for(size_t i = 0; i < size; ++i)
items[i].display_item();
}
private:
Item* items;
size_t capacity;
size_t size;
};

Incomplete type --> Can't Access Pointer value from my object

I'm trying to access one of my pointers within my class, however I can't seem to even get VS to acknowledge the pointer is there.
private:
ForwardTo* forward;
and here's how I grab it from the class
ForwardTo& Persons::getForwardTo() const
{
return *forward;
}
The ForwardTo type is an inherited class that typically reads:
class ForwardToTwo : public ForwardTo
{
public:
ForwardToTwo(unsigned int strategy);
virtual std::vector<std::string> forwardMessage(Persons& person, Message& message);
unsigned int getStrategy() const { return strategy;};
private:
unsigned int strategy;
};
and finally, here's how I'm trying to access the pointer
listOfPersons.at(i).getForwardTo()->forwardMessage(listOfPersons.at(i), tempMessage);
This style of access worked previously for my OTHER pointer in my class that acts exactly this same as this one.
While typing the line to access the pointer out in VS, intelliSense picks up all the functions up to getForwardTo(), and after that, the dot operator/arrow operator don't bring up any access to functions.
Thanks again for all help.
(edit, I'm aware the function fordwardMessage() function will return a vector, I was just typing in the VS until intelliSense failed to detect the accessible functions)
(edit 2, I've tried both the . operator and the -> operator, yet neither allow intelliSense to detect any functions.)
(edit 3, additional code:
Here is my Persons Class Header:
#ifndef PERSONS_HPP
#define PERSONS_HPP
#include <string>
#include <vector>
#include <list>
#include <map>
#include "Message.hpp"
#include "TypeOne.hpp"
#include "TypeTwo.hpp"
#include "TypeThree.hpp"
#include "TypeFour.hpp"
#include "TypeFive.hpp"
class ForwardTo;
class ForwardToOne;
class ForwardToTwo;
class ForwardToThree;
class Persons
{
public:
Persons();
~Persons();
void setEmailAddress(std::string email);
std::string getEmailAddress() const;
const std::vector<std::string>& getContactList() const;
void addMessageSeen(Message message);
void addMessageContent(MessageContent mc);
void addInboxMessage(Message message);
void addContact(std::string contact);
void viewContact(const std::vector<std::string>& contacts);
void bumpContact();
void setMessageTypeOne();
void setMessageTypeTwo(unsigned int type);
void setMessageTypeThree(unsigned int quality);
void setMessageTypeFour(unsigned int type, unsigned int quality);
void setMessageTypeFive();
void setForwardTypeOne(unsigned int strategy);
void setForwardTypeTwo(unsigned int strategy);
void setForwardTypeThree(unsigned int strategy);
void printPersonsObj();
std::list<Message> getInbox() const;
MessageType& getForwardWhen() const;
ForwardTo& getForwardTo() const;
private:
std::map<MessageContent, unsigned int> messageList;
std::list<Message> inbox;
std::vector<std::string> contactList;
std::string emailAddress;
ForwardTo* forward;
MessageType* forwardWhen;
};
And here is my Persons.cpp file is:
#include "Persons.hpp"
#include "ForwardToOne.hpp"
#include "ForwardToTwo.hpp"
#include "ForwardToThree.hpp"
#include <iostream>
Persons::Persons()
:emailAddress(""), contactList(), inbox(), messageList()
{
}
Persons::~Persons()
{
//delete forwardWhen;
//delete forwardTo;
}
void Persons::addMessageContent(MessageContent mc)
{
//messageSeen.insert(mc);
}
void Persons::setEmailAddress(std::string email)
{
emailAddress = email;
}
std::string Persons::getEmailAddress() const
{
return emailAddress;
}
void Persons::addContact(std::string contact)
{
contactList.push_back(contact);
}
void Persons::addInboxMessage(Message message)
{
inbox.push_back(message);
}
void Persons::viewContact(const std::vector<std::string>& contacts)
{
for(auto i = contacts.begin(); i != contacts.end(); i ++)
{
std::cout << *i << std::endl;;
}
}
void Persons::setMessageTypeOne()
{
MessageType* forwardWhen = new TypeOne();
}
void Persons::setMessageTypeTwo(unsigned int type)
{
MessageType* forwardWhen = new TypeTwo(type);
}
void Persons::setMessageTypeThree(unsigned int quality)
{
MessageType* forwardWhen = new TypeThree(quality);
}
void Persons::setMessageTypeFour(unsigned int type, unsigned int quality)
{
MessageType* forwardWhen = new TypeFour(type, quality);
}
void Persons::setMessageTypeFive()
{
MessageType* forwardWhen = new TypeFive();
}
void Persons::setForwardTypeOne(unsigned int strategy)
{
ForwardTo* forward = new ForwardToOne(strategy);
}
void Persons::setForwardTypeTwo(unsigned int strategy)
{
ForwardTo* forward = new ForwardToTwo(strategy);
}
void Persons::setForwardTypeThree(unsigned int strategy)
{
ForwardTo* forward = new ForwardToThree(strategy);
}
const std::vector<std::string>& Persons::getContactList() const
{
return contactList;
}
void Persons::bumpContact()
{
std::vector<std::string> tempList = getContactList();
std::string tempContact = tempList.at(0);
for(unsigned int i = 0; i <= tempList.size(); i ++)
{
if(i == tempList.size())
tempList.at(--i) = tempContact;
else
tempList.at(--i) = tempList.at(i);
}
}
void Persons::addMessageSeen(Message message)
{
messageList[*message.getMessageContent()] = message.getMessageContent()->getUniqueID();
}
void Persons::printPersonsObj()
{
std::cout << "PERSONS OBJECT!" << std::endl;
std::cout << "E-mail Address: " << emailAddress << std::endl;
std::cout << std::endl;
}
std::list<Message> Persons::getInbox() const
{
return inbox;
}
MessageType& Persons::getForwardWhen() const
{
return *forwardWhen;
}
ForwardTo& Persons::getForwardTo() const
{
return *forward;
}
Incomplete type normally means that at the point at which you are trying to use getForwardTo, you have not fully declared the ForwardTo class. Indeed in your persons.hop there is only a forward declaration.
Make sure you have included the header that fully declares ForwardTo in the file containing the call site.
getForwardTo() returns a T&, just use the . to access forwardMessage()

Typedef Student is not working

I am testing an array template. It works fine for string type and int, but not for a typedef Student. I tried to figure out, but I can't find the problem. I did not use a separate compilation as it is just a test. I am using Dev-C++. Your help will be very appreciated. The code is below:
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class Array
{
public:
Array(int initialSize);
~Array();
T & operator[](int i);
private:
T * m_pData;
int m_nSize;
};
//Implementing member functions in the Array template
template <typename T>
Array <T>::Array(int initialSize)
{
m_nSize = initialSize;
m_pData = new T [m_nSize];
};
template <typename T>
T & Array <T>::operator[](int i)
{
return m_pData[i];
};
template <typename T>
Array <T>::~Array()
{
delete[] m_pData;
};
typedef struct Student{}students[0];
//test array class implementatition
int main()
{
//creating an array of 20 integers, then assigning the value 50 at index 2
Array <int> myArray (20);
myArray[2] = 50;
cout << myArray[2] <<endl;
//creating an array of string of size 10, then assigning the string "Fred" at index 5
//then display the string
Array <string> nameArray (10);
nameArray[5] = string("Fred");
cout << nameArray[5] <<endl;
//creating an array of Student of size 100, then assigning the value "123456789" at index 4
//then display the value at that index
Array <Student> students (100);
students[4] = Student("123456789"); //here is the problem!!!
///cout << students[4] <<endl;
system ("pause");
return 0;
}
Student doesn't have a constructor,you can't call Student("123456789"); Try to define a constructor for Student:
struct Student
{
Student(): age_(0), name_("") {}
Student(int age): age_(age), name_("") {}
Student(const std::string& name): name_(name){
}
int age_;
std::string name_;
};