I need to create 2 classes, and second class must have pointer to first object as its member. My program works, but there are memory leaks, and I can't fix them. I know, that the problem is in constructor or destructor, but I don't know how to fix it. Here is my code:
main.cpp
#include "classes.h"
int main() {
COne firstObj;
CTwo secondObj;
firstObj.setN(10);
firstObj.setS("candies");
firstObj.print();
secondObj.setS("cookies");
secondObj.setP(&firstObj);
cout<<endl;
secondObj.print();
return 0;
}
classes.h
#ifndef CLASSES_H
#define CLASSES_H
#include <iostream>
#include <string>
using namespace std;
class COne {
private:
int n;
string sOne;
public:
COne(int n2create = 0, const string& sOne2create = "");
COne(const COne& obj);
~COne();
COne& operator=(const COne& obj);
void setN(int n2set);
void setS(const string &sOne2set);
int getN() const;
string getS() const;
void print() const;
};
class CTwo {
private:
string sTwo;
COne* p;
public:
CTwo(string sTwo2create = "", COne& p2create = *(new COne()));
CTwo(const CTwo& obj);
~CTwo();
CTwo& operator=(const CTwo& obj);
void setS(string sTwo2set);
void setP(COne* p2set);
string getS() const;
COne* getP() const;
void print() const;
};
#endif
classes.cpp
#include "classes.h"
COne::COne(int n2create, const string& sOne2create) :n(n2create), sOne(sOne2create) {}
COne::COne(const COne& obj) :n(obj.n), sOne(obj.sOne) {}
COne::~COne() {}
COne& COne::operator=(const COne& obj){
n = obj.n;
sOne = obj.sOne;
return *this;
}
void COne::setN(int n2set) {n = n2set;}
void COne::setS(const string& sOne2set) {sOne = sOne2set;}
int COne::getN() const {return n;}
string COne::getS() const {return sOne;}
void COne::print() const {
cout<<"COne object:"<<endl;
cout<<"n = "<<n<<endl;
cout<<"sOne = \""<<sOne<<"\""<<endl;
}
CTwo::CTwo(string sTwo2create, COne& p2create) :sTwo(sTwo2create), p(new COne(p2create)) {}
CTwo::CTwo(const CTwo& obj) :sTwo(obj.sTwo), p(new COne (*obj.p)){}
CTwo::~CTwo() {delete p;}
CTwo& CTwo::operator=(const CTwo& obj){
sTwo = obj.sTwo;
p = obj.p;
return *this;
}
void CTwo::setS(string sTwo2set) {sTwo = sTwo2set;}
void CTwo::setP(COne* p2set) {p = p2set;}
string CTwo::getS() const {return sTwo;}
COne* CTwo::getP() const {return p;}
void CTwo::print() const {
cout<<"CTwo object:"<<endl;
cout<<"sTwo = \""<<sTwo<<"\""<<endl;
cout<<"p: n = "<<p->getN()<<", sOne = \""<<p->getS()<<"\""<<endl;
}
For one, in:
COne& p2create = *(new COne())
You have a memory leak if the argument is default constructed. This is because p2create is a reference to a dynamically allocated object and you then copy it into another dynamically allocated object only to store the latter and never free the former.
Specifically in:
CTwo::CTwo(string sTwo2create, COne& p2create) :sTwo(sTwo2create), p(new COne(p2create)) {}
Your code contains other errors of course. To solve them all, just rewrite your classes to:
struct COne {
int n;
std::string s;
void print() const {
std::cout << "COne object:\n"
<< "n = " << n << '\n'
<< "s = \"" << s << "\"\n";
}
};
struct CTwo {
std::string sTwo;
COne p;
void print() const {
std::cout << "CTwo object:\n"
<< "sTwo = \"" << sTwo << "\"\n"
<< "p: n = "<< p.n << ", s = \"" << p.s <<"\"\n";
}
};
which are functionally equivalent, and then use them as:
int main() {
COne firstObj {10, "candies"};
firstObj.print();
std::cout << '\n';
CTwo secondObj {"cookies", firstObj};
secondObj.print();
return 0;
}
Live demo
void CTwo::setP(COne* p2set) {p = p2set;}
Saves the new pointer, overwriting the previous value of p without deleting any previously allocated memory assigned to p.
Related
This will be a bit lengthy but anyhow i tried my best to simplify it using code.
I am building a binary tree but noticed something peculiar.
linked_binary_tree.h
#ifndef LINKED_BINARY_TREE_H
#define LINKED_BINARY_TREE_H
#include <iostream>
#include <list>
using namespace std;
typedef int Elem;
class LinkedBinaryTree {
protected:
struct Node {
Elem ele;
Node *par;
Node *left;
Node *right;
Node(): ele(), par(NULL), left(NULL), right(NULL) {}
};
public:
class Position {
friend LinkedBinaryTree;
private:
Node *v;
public:
Position(Node *_v=NULL): v(_v) { cout << "Position constr" << endl;}
Elem &operator*() const {
return v->ele;
}
Position left() const {
return Position (v->left);
}
Position right() const {
return Position (v->right);
}
Position parent() const {
return Position(v->par);
}
bool isRoot() const {
return v->par==NULL;
}
bool isExternal() const {
return v->left==NULL && v->right==NULL;
}
};
typedef list<Position> PositionList;
LinkedBinaryTree();
int size() const;
bool empty() const;
Position root() const;
PositionList positions(int trv) const;
void addRoot();
void expandExternal(const Position &p);
Position removeAboveExternal(const Position &p);
protected:
void preorder(Node *v, PositionList &pl) const;
void postorder(Node *v, PositionList &pl) const;
void inorder(Node *v, PositionList &pl) const;
private:
Node * _root;
int n;
};
#endif
linked_binary_tree.cc
#include <iostream>
#include <list>
#include "linked_binary_tree.h"
using namespace std;
LinkedBinaryTree::LinkedBinaryTree(): _root(NULL), n(0) {}
int LinkedBinaryTree::size() const {
return n;
}
bool LinkedBinaryTree::empty() const {
return size()==0;
}
LinkedBinaryTree::Position LinkedBinaryTree::root() const {
cout << "LinkedBinaryTree::root()" << endl;
return Position(_root);
}
void LinkedBinaryTree::addRoot() {
_root=new Node;
n=1;
_root->ele=n;
}
void LinkedBinaryTree::expandExternal(const Position &p) {
Node *v = p.v;
v->left=new Node;
v->left->par=v;
v->left->ele=++n;
v->right=new Node;
v->right->par=v;
v->right->ele=++n;
}
LinkedBinaryTree::PositionList LinkedBinaryTree::positions(int trv) const {
PositionList pl;
if (trv==1)
preorder(_root,pl);
else if (trv==2)
inorder(_root,pl);
else postorder(_root,pl);
return PositionList(pl);
}
void LinkedBinaryTree::preorder(Node *v, PositionList &pl) const {
pl.push_back(Position(v));
if (v->left!=NULL)
preorder(v->left,pl);
if (v->right!=NULL)
preorder(v->right,pl);
}
void LinkedBinaryTree::postorder(Node *v, PositionList &pl) const {
if (v->left!=NULL)
preorder(v->left,pl);
if (v->right!=NULL)
preorder(v->right,pl);
pl.push_back(Position(v));
}
void LinkedBinaryTree::inorder(Node *v, PositionList &pl) const {
if (v->left!=NULL)
preorder(v->left,pl);
pl.push_back(Position(v));
if (v->right!=NULL)
preorder(v->right,pl);
}
linked_binary_tree_main.cc
#include <iostream>
#include "linked_binary_tree.h"
using namespace std;
int main() {
LinkedBinaryTree lbt;
lbt.addRoot();
cout << "post addRoot()" << endl;
LinkedBinaryTree::Position pr = LinkedBinaryTree::Position(lbt.root()); // --> STATEMENT 1
cout << "post lbt.root()" << endl;
//LinkedBinaryTree::Position pr = lbt.root(); // --> STATEMENT 2
lbt.expandExternal(pr);
cout << "LinkedBinaryTree.size() :- " << lbt.size() << endl;
// 1-preorder 2-inorder 3-postorder
auto iter=lbt.positions(3);
auto cbeg=iter.cbegin();
auto cend=iter.cend();
for (; cbeg!=cend; cbeg++) {
cout << cbeg->operator*() << " ";
}
cout << endl;
return 0;
}
Results executing linked_binary_tree_main
post addRoot()
LinkedBinaryTree::root() --> STATEMENT 3
Position constr --> STATEMENT 4
post lbt.root()
LinkedBinaryTree.size() :- 3
Position constr
Position constr
Position constr
2 3 1
Note:
Statement 1
LinkedBinaryTree::Position pr = LinkedBinaryTree::Position(lbt.root()); // --> STATEMENT 1
a. The lbt.root() actually returned LinkedBinaryTree::Position instance.
b. There is no LinkedBinaryTree::Position constructor which takes in a Position instance. Instead it has the following:
Position(Node *_v=NULL): v(_v) { cout << "Position constr" << endl;}
which is it takes a pointer to a Node argument. Yet STATEMENT 1 works showing that LinkedBinaryTree::Position(Node *v) constructor is called.
c. If you comment out STATEMENT 1 and use STATEMENT 2 that of course would work as well.
So why does STATEMENT 1 works?
Appreciate any insight.
Thanks.
The constructor you're seeing is not the one you think it is.
The constructor in STATEMENT 1 is the (compiler-generated) copy-constructor.
The constructor printing the output Position constr happens in the LinkedBinaryTree::root function:
return Position(_root);
This was much easier to see once I created a more minimal example (together with some extra output).
This question already has answers here:
What is The Rule of Three?
(8 answers)
What are the basic rules and idioms for operator overloading?
(8 answers)
Closed 7 months ago.
Please explain to me why the destructor gets called on the "strand" object after its assigned with "tari" members. this question has been puzzling me and I haven't been able to move on from it as it gives me the wrong answer of 5 at the end instead of 10 when i try to add the contents of the "jesu" objects because the destructor gets called and any operation done on strand object becomes obsolete
#include <iostream>
#include <iomanip>
using namespace std;
class Bheki
{
private:
string name;
int sam;
double *jesu = nullptr;
public:
Bheki(){}
void Hvo()
{
jesu = new double(5);
}
double* getJesu() const
{
return jesu;
}
void setName(string Gama){name = Gama;}
void setSam(int ram){sam=ram;}
string getName()const{
return name;
}
int getSam()const{
return sam;
}
~Bheki(){
delete jesu;
jesu = nullptr;
}
const Bheki operator=(const Bheki &);
const Bheki operator+(const Bheki &);
};
const Bheki Bheki::operator+(const Bheki &ned)
{
Bheki temp;
temp.sam = sam + ned.sam;
temp.jesu = new double();
*temp.jesu = (*jesu) + (*ned.jesu);
cout<<*temp.jesu<<endl;
return temp;
}
const Bheki Bheki::operator =(const Bheki &pop)
{
if(this != &pop)
{
this->name = pop.name;
this->sam =pop.sam;
this->jesu = new double{};
*this->jesu = *pop.jesu;
}
return *this;
}
int main()
{
Bheki *tari = new Bheki();
tari->Hvo();
tari->setName("jece");
tari->setSam(6969);
cout<<tari->getName()<<endl;
Bheki *strand = new Bheki;
*strand = *tari;
cout<<strand->getName()<<endl;
strand->setName("Kumkani");
cout<<tari->getName()<<endl;
*strand->getJesu()=20.325;
cout<<strand->getJesu()<<endl;
cout<<tari->getJesu()<<endl;
*strand->getJesu() = 32;
cout<<*tari->getJesu()<<endl;
strand->setSam(884);
tari-> setSam(7);
cout<<*tari->getJesu()<<endl;
*strand->getJesu() = 5;
*tari->getJesu() = 5;
Bheki *balo = new Bheki;
*balo = *strand + *tari;
cout<<*balo->getJesu()<<endl;
cout<<balo->getSam()<<endl;
// delete tari;
// delete balo;
// delete strand;
return 0;
}
I compare my code with another post I found posted by #Serge Rogatch who said that it does not get called at assignment but mine does get called which completely contradicts each other
#include <iostream>
#include <string>
class Test
{
std::string _name;
public:
Test(std::string name ="") : _name(name) { }
~Test()
{
std::cout << "Destructor " << _name << std::endl;
}
Test& operator=(const Test& fellow)
{
// avoid changing the name of the object
std::cout << "Assignment operator "
<< _name << "=" << fellow._name << std::endl;
return *this;
}
};
int main()
{
Test t1, t2("t2");
t1 = t2;
return 0;
}
I want Swap the name (i.e. string in cName[]) of the two cats using the pointer approach.
However I want to Only swap the name, NOT the object.
Am I correct?
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;
class CAT
{
public:
CAT(char * firstname) { strncpy(cName, firstname, 79); }
~CAT() { ; }
char * getName() { return cName; }
void setName(char *nameinput) { strncpy(cName, nameinput, 79); }
private:
char cName[80];
};
void nameSwap(CAT *CatA, CAT *CatB)
{
char testing[] = "testing";
CAT temp =CAT(testing);
temp = *CatA;
*CatA = *CatB;
*CatB = temp;
}
int main()
{
char Taby[] = "Taby";
char Felix[] = "Felix";
CAT pA = CAT(Taby);
CAT pB = CAT(Felix);
cout << "The inital name pA is " << pA.getName() << " and pA is" << pB.getName() << endl;
nameSwap(&pA, &pB);
cout << "After approach" << endl;
cout << "The name pA is " << pA.getName() << " and " << pB.getName() << endl;
system("PAUSE");
return 0;
}
You are actually swapping the whole objects, not only the name of the CAT.
If you only want to swap the name, you need to access the cName member in a similar way as you are doing for the objects. You'd also need permission to access to the cName member in such a swap function, which a function outside won't have since cName is private. Make the swap function a member of your class:
class CAT
{
public:
CAT(const char* firstname) { strncpy(cName, firstname, 80); }
~CAT() {}
const char* getName() const { return cName; }
void setName(const char *nameinput) { strncpy(cName, nameinput, 80); }
void swapName(CAT& CatB)
{
char tmp[80];
strncpy(tmp, CatB.cName, 80);
strncpy(CatB.cName, cName, 80);
strncpy(cName, tmp, 80);
}
private:
char cName[80];
// other CAT attributes won't be affected by the name swap
};
And call it like this
pA.swapName(pB); // or pB.swapName(pA); - same result
But consider using std::string instead of char[]. You'll soon find C++ strings much easier to work with and also, when swapping those, only the pointers to the underlying memory is swapped, so it's more effective.
std::string one;
std::string two;
one.swap(two);
Edit: As per request, I added a version using pointers.
I made it in a haste and haven't debugged it so I've probably made a lot of mistakes. First, I made a new class called wong_string that will hold the name and any other attributes suiteable for strings.
#include <stdexcept>
#include <cstring>
class wong_string {
char* m_data;
static char* duplicate(const char* str) {
size_t len = std::strlen(str)+1;
char* rv = new char[len];
std::memcpy(rv, str, len);
return rv;
}
public:
// default constructor: wong_string howdy1;
wong_string() : m_data(nullptr) {}
// conversion constructor: wong_string howdy2("value2");
wong_string(const char* cstr) :
m_data(duplicate(cstr))
{}
// copy constructor: wong_string howdy3 = howdy2;
wong_string(const wong_string& rhs) : wong_string(rhs.m_data) {}
// move constructor: wong_string howdy4 = wong_string("value4");
wong_string(wong_string&& rhs) : m_data(rhs.m_data) {
rhs.m_data = nullptr;
}
// copy assignment operator: (wong_string howdy5;) howdy5 = howdy4;
wong_string& operator=(const wong_string& rhs) {
if(this!=&rhs) {
char* tmp = duplicate(rhs.m_data);
if(m_data) delete []m_data;
m_data = tmp;
}
return *this;
}
// copy assignment operator from c string
wong_string& operator=(const char* rhs) {
*this = wong_string(rhs);
return *this;
}
// move assignment operator: (wong_string howdy6;) howdy6 = wong_string("value6");
wong_string& operator=(wong_string&& rhs) {
if(this!=&rhs) {
m_data = rhs.m_data;
rhs.m_data = nullptr;
}
return *this;
}
// destructor, free memory allocated by duplicate(), if any
~wong_string() {
if(m_data) delete []m_data;
}
// comparisons
bool operator==(const wong_string& rhs) const {
return strcmp(m_data, rhs.m_data)==0;
}
bool operator!=(const wong_string& rhs) const {
return !(*this==rhs);
}
// conversion to a normal c string
operator char const* () const { return m_data; }
// output stream operator
friend std::ostream& operator<<(std::ostream&, const wong_string&);
// input stream operator - not implemented yet
};
with that in place, your CAT can be made into something like this:
class CAT
{
public:
CAT(const char* firstname, const char* nickname=nullptr) :
cName(firstname),
cNickName(nickname?nickname:firstname)
{}
~CAT() {}
const char* getName() const { return cName; }
void setName(const char *nameinput) { cName=nameinput; }
void swapName(CAT& CatB)
{
std::swap(cName, CatB.cName);
}
private:
wong_string cName; // Madame Florence Jenkins III
// other CAT attributes won't be affected by the name swap
wong_string cNickName; // Ms. Miao
};
So, there you have it. Pointers galore...
###MyClass.h###
#ifndef _MyClass
#define _MyClass
#include <string>
using namespace std;
class MyClass
{
public:
MyClass(const string name, const string text);
void display(ostream & out) const;
MyClass & operator = (const MyClass & m);
int compare(const MyClass & right) const;
private:
string _name;
string _text;
};
bool operator < (const MyClass & left, const MyClass & right);
ostream & operator << (ostream & out, const MyClass & mc);
#endif
###Node.h###
#include <string>
#include "MyClass.h"
using namespace std;
typedef MyClass * DataType;
class Node
{
private:
DataType item; // data
Node * lchild; // left child pointer
Node * rchild; // right child pointer
public:
Node(DataType Item);
DataType getItem() const;
void setItem(const DataType & data);
Node* getLChild() const;
void setLChild(Node * p);
Node* getRChild() const;
void setRChild(Node * p);
virtual ~Node();
};
###BST.h###
#include "Node.h"
using namespace std;
class BST
{
private:
Node * root;
bool Search(const DataType item, Node * r) const;
void Insert (DataType item, Node * ptr);
void Destructor(const Node * r);
public:
BST();
bool IsEmpty() const;
void Insert(const DataType item);
bool Search(const DataType item) const;
virtual ~BST();
};
###MyClass.cpp###
#include <iostream>
#include "MyClass.h"
using namespace std;
MyClass::MyClass(const string name, const string text)
{
_name = name;
_text = text;
}
void MyClass::display(ostream & out) const
{
out << "Name: " << _name << endl;
out << "Text: " << _text << endl;
}
MyClass & MyClass::operator = (const MyClass & m)
{
if (this == & m)
return *this;
_name = m._name;
_text = m._text;
return *this;
}
int MyClass::compare(const MyClass & right) const
{
return _name.compare(right._name);
}
bool operator < (const MyClass & left, const MyClass & right)
{
return left.compare(right) > 0;
}
ostream & operator << (ostream & out, const MyClass & mc)
{
mc.display(out);
return out;
}
###Node.cpp###
#include "Node.h"
Node::Node(DataType Item):item(Item)
{
lchild = 0;
rchild = 0;
}
DataType Node::getItem() const
{
DataType anItem = item;
return anItem;
}
void Node::setItem( const DataType & data)
{
item = data;
}
Node* Node::getLChild() const
{
Node * p = lchild;
return p;
}
void Node::setLChild(Node * p)
{
lchild = p;
}
Node* Node::getRChild() const
{
Node * p = rchild;
return p;
}
void Node::setRChild(Node * p)
{
rchild = p;
}
Node::~Node()
{
}
###BST.cpp###
#include <iostream>
#include "BST.h"
using namespace std;
bool BST::Search(const DataType item) const
{
return Search(item, root);
}
bool BST::Search(const DataType item, Node * r) const
{
if(r != 0)
{
if (item == r->getItem())
return true;
else
{
if (item < r->getItem())
return Search(item, r->getLChild());
else
return Search(item, r->getRChild());
}
}
else
return false;
}
BST::BST()
{
root = 0;
}
bool BST::IsEmpty() const
{
return (root == 0);
}
void BST::Insert(const DataType item)
{
if(root == 0)
root = new Node(item);
else
Insert(item, root);
}
void BST::Insert(DataType item, Node * ptr)
{
if (item < ptr->getItem())
{
if (ptr->getLChild() == 0)
ptr->setLChild(new Node(item));
else
Insert(item, ptr->getLChild());
}
else
{
if (ptr->getRChild() == 0)
ptr->setRChild(new Node(item));
else
Insert(item, ptr->getRChild());
}
}
void BST::Destructor(const Node * r)
{
if(r!=0)
{
Destructor( r->getLChild());
Destructor( r->getRChild());
delete r;
}
}
BST::~BST()
{
Destructor(root);
}
###main.cpp###
#include <iostream>
#include "MyClass.h"
#include "BST.h"
using namespace std;
void main()
{
MyClass * mc1 = new MyClass("Tree","This is a tree");
MyClass * mc2 = new MyClass("Book","This is a book");
MyClass * mc3 = new MyClass("Zoo","This is a zoo");
BST * tree = new BST();
tree->Insert(mc1);
tree->Insert(mc2);
tree->Insert(mc3);
cout << boolalpha << ("Book" < "Tree") << endl;
cout << (mc2 < mc1) << endl;
cout << (tree->Search(new MyClass("Book",""))) << endl;
}
Result is true false false
I don't know what's wrong with my operator overloading? (mc2 should
less than mc1)
I'm not sure if this is correct for searching a "MyClass" node in a BST?
and the result is "not found"....I traced it into "BST.cpp",
and found that the problem also occurs at " if (item < r->getItem()) "
Can anyone help me or give me a hint....thank you so much!
Here you are just comparing pointers, i.e memory addresses:
cout << (mc2 < mc1) << endl;
To compare the objects, you need to dereference the pointers:
cout << ((*mc2) < (*mc1)) << endl;
In your code snippet, there is no reason for mc1, mc2, etc. to be pointers, so you could avoid the problem by creating objects on the stack directly:
MyClass mc1("Tree","This is a tree");
and so on. I would even go further and say that you should only dynamically allocate objects with new if you really are sure you need to and have good reasons not to allocate automatically on the stack. And if you really must use dynamically allocated pointers, have a look at C++ smart pointers.
Ok, so I know there are probably a lot of errors in this code. I'm pretty new to dynamic memory allocation, pointers, etc.
The header file, account.h, is given to us by our professor. We were told not to make any changes to the .h file.
The implementation file is written by me. The main function is included just for basic initial testing. We were given another file to actually test the implementation of the account class.
If I don't comment out the cout name line, I get a seg fault 11 error.
If I do, it'll print the account number, but throw this error:
Test(29976) malloc: * error for object 0x62c1aa18c9d8374: pointer being freed was not allocated* set a breakpoint in malloc_error_break to debug
Abort trap: 6
Any help at all would be greatly appreciated!
Here's the header file:
class account
{
public:
typedef char* string;
static const size_t MAX_NAME_SIZE = 15;
// CONSTRUCTOR
account (char* i_name, size_t i_acnum, size_t i_hsize);
account (const account& ac);
// DESTRUCTOR
~account ( );
// MODIFICATION MEMBER FUNCTIONS
void set_name(char* new_name);
void set_account_number(size_t new_acnum);
void set_balance(double new_balance);
void add_history(char* new_history);
// CONSTANT MEMBER FUNCTIONS
char* get_name ( ) const;
size_t get_account_number ( ) const;
double get_balance( ) const;
size_t get_max_history_size( ) const;
size_t get_current_history_size ( ) const;
string* get_history( ) const;
friend ostream& operator <<(ostream& outs, const account& target);
private:
char name[MAX_NAME_SIZE+1]; //name of the account holder
size_t ac_number; //account number
double balance; //current account balance
string *history; //Array to store history of transactions
size_t history_size; //Maximum size of transaction history
size_t history_count; //Current size of transaction history
};
Here is the implementation file:
// File: account.cxx
// Author: Mike Travis
// Last Modified: Mar 3, 2012
// Description: implementation of Account class as prescribed by the file account.h
#include <cstdlib>
#include <stdio.h>
#include <iostream>
#include "account.h"
using namespace std;
//Constructor
account::account(char* i_name, size_t i_acnum, size_t i_hsize){
string *d_history;
d_history = new string[i_hsize];
for(int i = 0; i<i_hsize; i++){
name[i] = i_name[i];
}
ac_number = i_acnum;
history_size = i_hsize;
history_count = 0;
}
account::account(const account& ac){
string *d_history;
d_history = new string[ac.history_size];
for( int i=0; i<ac.get_current_history_size(); i++){
strcpy(d_history[i], history[i]);
}
strcpy(name,ac.get_name());
ac_number = ac.get_account_number();
history_size = ac.get_max_history_size();
history_count = ac.get_current_history_size();
}
account::~account(){ delete [] history; }
void account::set_name(char* new_name){ strcpy(name, new_name); }
void account::set_account_number(size_t new_acnum){ ac_number = new_acnum; }
void account::set_balance(double new_balance){ balance = new_balance; }
void account::add_history(char* new_history){
strcpy(history[history_count], new_history);
history_count++;
}
char* account::get_name() const {
char* name_cpy;
strcpy(name_cpy, name);
return name_cpy;
}
size_t account::get_account_number() const{ return ac_number; }
double account::get_balance() const{ return balance; }
size_t account::get_max_history_size() const{ return history_size; }
size_t account::get_current_history_size() const{ return history_count; }
//string* account::get_history() const{ return *history; }
int main(){
account test1("mike travis", 12345, 20);
//cout<<"\nname: "<< test1.get_name();
cout<<"\n\nacnum: "<<test1.get_account_number()<<"\n\n";
return 0;
}
In the destructor of account, you delete the history array. However, in the constructor, you allocate (and leak) an array which is stored in the local variable d_history. You presumably wanted to assign that to the member variable history instead - since you haven't, if you get to the destructor it gives you an error saying that you're freeing history but have never allocated it.
There's a similar error in the copy constructor as well.
There are also other errors in your code as well, which I assume you'll find as you go - get_name(), for example, is not going to work. I suspect the header file is not helping here, but there's not much to be done if you're not supposed to change that.
I've written a little bit code for you and corrected the epic mistakes (even in the header file, sorry ;)). It is still extremely ugly and c-ish, but maybe you can learn something reading it:
#include <cstddef>
#include <ostream>
class account
{
// The whole class makes no sense, since it has no useful
// member function or anything like this.
// Furthermore, the class provides almost full access to all its member variables.
// At this point one could just make everything public.
// This is not even exception safe when the constructor throws.
// A good implementation would use history_entry and history classes,
// together with std::string and std::vector/std::deque
// And it would provide some sort of functionality. ;)
public:
account(const char* name, unsigned number, std::size_t history_max_size);
account(const account& other);
~account();
const char* name() const;
unsigned number() const;
double balance() const;
const char* const* history() const;
std::size_t history_size() const;
unsigned history_max_size() const;
void set_name(const char* new_name);
void set_number(unsigned new_number);
void set_balance(double new_balance);
void add_history(const char* new_history);
private:
char* name_;
unsigned number_;
double balance_;
char** history_;
std::size_t history_size_;
const std::size_t history_max_size_;
};
std::ostream& operator << (std::ostream& stream, const account& a);
#include <cassert>
#include <cstring>
account::account(const char* name, unsigned number, std::size_t history_max_size)
: name_(0)
, number_(number)
, balance_(0.0)
, history_(new char*[history_max_size])
, history_size_(0)
, history_max_size_(history_max_size)
{
assert(name != 0);
assert(history_max_size != 0);
set_name(name);
}
account::account(const account& other)
: name_(0)
, number_(other.number_)
, balance_(other.balance_)
, history_(new char*[other.history_max_size_])
, history_size_(other.history_size_)
, history_max_size_(other.history_max_size_)
{
set_name(other.name_);
for (std::size_t i = 0; i != other.history_size_; ++i)
{
history_[i] = new char[std::strlen(other.history_[i]) + 1];
strcpy(history_[i], other.history_[i]);
}
}
account::~account()
{
delete[] name_;
for (std::size_t i = 0; i != history_size_; ++i)
delete[] history_[i];
delete[] history_;
}
const char* account::name() const
{
return name_;
}
unsigned account::number() const
{
return number_;
}
double account::balance() const
{
return balance_;
}
const char* const* account::history() const
{
return history_;
}
std::size_t account::history_size() const
{
return history_size_;
}
unsigned account::history_max_size() const
{
return history_max_size_;
}
void account::set_name(const char* new_name)
{
if (name_)
delete[] name_;
name_ = new char[std::strlen(new_name) + 1];
std::strcpy(name_, new_name);
}
void account::set_number(unsigned new_number)
{
number_ = new_number;
}
void account::set_balance(double new_balance)
{
balance_ = new_balance;
}
void account::add_history(const char* new_history)
{
if (history_size_ == history_max_size_)
{
delete[] history_[0]; // delete oldest entry
for (std::size_t i = 0; i != history_size_ - 1; ++i)
history_[i] = history_[i + 1];
--history_size_;
}
history_[history_size_] = new char[strlen(new_history) + 1];
std::strcpy(history_[history_size_], new_history);
++history_size_;
}
std::ostream& operator << (std::ostream& stream, const account& a)
{
return stream << "account [name: " << a.name() << ", number: "
<< a.number() << ", balance: " << a.balance() << ']';
}
#include <iostream>
int main()
{
account a("Hello!", 500, 5);
a.set_balance(12.546);
for (int i = 50; i--; )
a.add_history("Yaaay..");
//account b = a;
std::cout << a << '\n';
}