This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I am just beginning with programming in c++ (IDE is CodeBlocks).
I wrote two simple classes (Song and Metadata) and testing around with sqlite.
The Problem: My program seems to get insufficient memory: When I start the program it either crashes immediately or the sqlite3_open command returns the error "out of memory". When I test the SQLITE function without any other code, it works!
So this does not work:
#include <iostream>
#include "metadata.h"
#include "Song.h"
#include <cstdio>
#include "sqlite3.h"
using namespace std;
int main()
{
// Without this block it DOES work!
Metadata* tmpMeta = new Metadata("Eiffel 65", "Blue", "Europop");
Song* tmpSong;
tmpSong = new Song();
tmpSong->set_metadata(*tmpMeta);
// end of block
sqlite3 *db;
int rc;
rc = sqlite3_open_v2("test.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL);
cout << "Result: " << sqlite3_errmsg(db) << '\n';
sqlite3_close(db);
return 0;
}
Please see the Song and Metadata classes attached.
I do not know how to react to this error.
My environment:
- Windows 8, 64 bit
- Code::Blocks 10.05
- Compiler: GNU GCC Compiler
Thank you in advance!
Greetings
Sebastian
Song.h:
#include <iostream>
#include <cstring>
#include "metadata.h"
using namespace std;
class Song {
private:
Metadata metadata;
unsigned int iD;
char filename[400];
public:
//Constructors
Song( Metadata, unsigned int, const char*);
Song( );
//Methods
void set_metadata(Metadata& meta);
void set_id(unsigned int i);
void set_filename(const char* f);
Metadata get_metadata();
unsigned int get_id();
const char* get_filename();
};
Song.cpp:
#include <iostream>
#include "Song.h"
using namespace std;
Song::Song(Metadata m, unsigned int id, const char* f) {
metadata = m;
iD = id;
strncpy(filename, f, sizeof(filename)-1);
filename[sizeof(filename)] = '\0';
}
Song::Song( ) {
Metadata tmpMeta;
metadata = tmpMeta;
iD = 0;
strncpy(filename, "unknown", sizeof(filename) -1);
filename[sizeof(filename)] = '\0';
}
void Song::set_filename(const char* f) {
strncpy( filename, f, sizeof(filename)-1 );
filename[sizeof(filename)] = '\0';
}
void Song::set_id(unsigned int i) {
iD = i;
}
void Song::set_metadata(Metadata& meta) {
metadata = meta;
}
Metadata Song::get_metadata() {
return metadata;
}
const char* Song::get_filename() {
return filename;
}
unsigned int Song::get_id() {
return iD;
}
Metadata.h:
#include <iostream>
#include <cstring>
#ifndef _METADATA_H_
#define _METADATA_H_
using namespace std;
class Metadata {
private:
unsigned int trackNumber;
char artist[20];
char title[20];
unsigned int year;
char genre[20];
char album[20];
public:
Metadata(const char*, const char*, const char*);
const char* get_artist();
const char* get_title();
const char* get_album();
const char* get_genre();
unsigned int get_trackNumber();
unsigned int get_year();
void set_artist(const char*);
void set_title(const char*);
void set_album(const char*);
void set_genre(const char*);
void set_year(unsigned int);
void set_trackNumber(unsigned int);
};
#endif
Metadata.cpp:
#include <iostream>
#include "metadata.h"
Metadata::Metadata(const char* ar, const char* tit, const char* al) {
trackNumber = 0;
year = 0;
strncpy(genre, "unknown", sizeof(genre) -1);
genre[sizeof(genre)] = '\0';
strncpy(artist, ar, sizeof(artist) -1);
artist[sizeof(artist)] = '\0';
strncpy(title, tit, sizeof(title) -1);
title[sizeof(title)] = '\0';
strncpy(album, al, sizeof(album) -1);
album[sizeof(album)] = '\0';
}
const char* Metadata::get_artist() {
return artist;
}
const char* Metadata::get_title() {
return title;
}
const char* Metadata::get_album() {
return album;
}
const char* Metadata::get_genre() {
return genre;
}
void Metadata::set_artist(const char* ar) {
strncpy(artist, ar, sizeof(artist) -1);
artist[sizeof(artist)] = '\0';
}
void Metadata::set_title(const char* tit) {
strncpy(title, tit, sizeof(title) -1);
title[sizeof(title)] = '\0';
}
void Metadata::set_album(const char* al) {
strncpy(album, al, sizeof(album) -1);
album[sizeof(album)] = '\0';
}
void Metadata::set_genre(const char* g) {
strncpy(genre, g, sizeof(genre) -1);
genre[sizeof(genre)] = '\0';
}
void Metadata::set_trackNumber(unsigned int tn) {
trackNumber = tn;
}
void Metadata::set_year(unsigned int y) {
year = y;
}
For starters: All your string termination code is wrong in Metadata.cpp and Song.cpp:
Example:
strncpy(genre, "unknown", sizeof(genre) -1);
genre[sizeof(genre)] = '\0';
The call to strncpy() is correct. The hard-terminator is NOT. it should be:
strncpy(genre, "unknown", sizeof(genre) -1);
genre[sizeof(genre) -1] = '\0';
This is replicated on all your strings. recheck them all. it will surface several side-effects until you fix them. Considering these objects are all heap-allocated, you're corrupting your heap on the improper termination of Song::filename[] and MetaData::albumin[]. Don't just fix those two; fix them all.
Remember. sizeof() returns an octet-count of the field passed. which means char field[N]; will return N. if you already know C/C++ you know arrays are zero-based and therefore field[N-1] is the maximum allowable index.
Related
I have a class called Person:
class Person {
private:
char name[50];
unsigned int number;
public:
void set_data(const char *newname, unsigned int number) {
*name= *newname; //THE MAIN PROBLEM I WANT TO SOLVE
this->number = number;
}
char* get_name() {
return this->name;
}
unsigned int get_number() {
return this->number;
}
};
I have arrays:
const char *names[] = {"Mark", "Pavel", "Bill", "Jasur", "Jeff"};
int phones[] = { 1234567890, 9876543210, 123321456654, 1998946848479, 1234554321 };
I'm using for loop to set Person members:
Person p;
for (int i = 0; i < 5; i++) {
p.set_data(names[i], phones[i]);
cout << p.get_name() << endl;
}
When I run this, I'm getting wrong output.
Using * the way you are, you are only copying the 1st char into name. You are also not null-terminating name either, which is required by the overloaded operator<< that takes a char* as input.
To copy the entire string, you need to use std::strcpy() (or better, std::strncpy()) instead, eg:
#include <cstring>
void set_data(const char *newname, unsigned int newnumber) {
//std::strcpy(name, newname);
std::strncpy(name, newname, 49);
name[49] = '\0';
number = newnumber;
}
However, since this is C++ and not C, you really should be using std::string instead:
#include <string>
class Person {
private:
std::string name;
unsigned int number;
public:
void set_data(const std::string &newname, unsigned int newnumber) {
name = newname;
number = newnumber;
}
std::string get_name() const {
return name;
}
/* or:
const std::string& get_name() const {
return name;
}
*/
unsigned int get_number() const {
return number;
}
};
Here is my program
Contact.h
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
#pragma once
class Contact
{
private:
char *Name;
char *Last;
int Phone;
char *Address;
public:
Contact operator +(Contact NewVal);
Contact(char *newName,char *newLastName,char *newAddress,int newPhone);
Contact(void);
~Contact(void);
void SetName(char *newName);
void SetLastName(char *newLastName);
void SetAddress(char *newAddress);
void SetPhone(int newPhone);
char* Contact::GetLast(void);
char* Contact::GetAddress(void);
int Contact::GetPhone(void);
char* GetName(void);
};
Contact.cpp
#include "StdAfx.h"
#include "Contact.h"
Contact::Contact(void)
{
}
Contact::Contact(char *newName,char *newLastName,char *newAddress,int newPhone)
{
SetName(newName);
SetLastName(newLastName);
SetAddress(newAddress);
SetPhone(newPhone);
}
Contact::~Contact(void)
{
}
void Contact::SetName(char *newName){
Name=_strdup(newName);
}
void Contact::SetLastName(char *newLastName){
Last=strdup(newLastName);
}
void Contact::SetAddress(char *newAddress){
Address=strdup(newAddress);
}
void Contact::SetPhone(int newPhone){
Phone=newPhone;
}
char* Contact::GetName(void)
{
return Name;
}
char* Contact::GetLast(void)
{
return Last;
}
char* Contact::GetAddress(void)
{
return Address;
}
int Contact::GetPhone(void)
{
return Phone;
}
Contact Contact::operator+(Contact NewVal)
{
//strcat(this->Address,NewVal.Address);
//strcat(this->Last,NewVal.Last);
//strcat(this->Name,NewVal.Name);
this->Phone=this->Phone+NewVal.Phone;
sprintf(this->Address,"%s %s",this->Address,NewVal.Address);
sprintf(this->Name,"%s %s",this->Name,NewVal.Name);
sprintf(this->Last,"%s %s",this->Last,NewVal.Last);
return *this;
}
Phonebook.h
#include "Contact.h"
#pragma once
class PhoneBook
{
private:
Contact member[100];
int ID;
public:
PhoneBook(void);
~PhoneBook(void);
Contact Search(char* newName);
bool AddNewContact(char* NewName, char* NewLast, char* NewAddress,int NewPhone);
void ShowContacts(void);
};
PhoneBook.Cpp
#include "StdAfx.h"
#include "PhoneBook.h"
PhoneBook::PhoneBook(void)
{
}
PhoneBook::~PhoneBook(void)
{
}
Contact PhoneBook::Search(char* newName)
{
return Contact();
}
bool PhoneBook::AddNewContact(char* NewName, char* NewLast, char* NewAddress,int NewPhone)
{
ID=ID+1;
member[ID].SetName(NewName);
member[ID].SetLastName(NewLast);
member[ID].SetAddress(NewAddress);
member[ID].SetPhone(NewPhone);
return true;
}
void PhoneBook::ShowContacts(void)
{
for(int a=0;a<=ID;a++){
cout<<"Name:"<<member[ID].GetName()<<endl<<"LastName:"<<member[ID].GetLast()<<endl<<"Address:"<<member[ID].GetAddress()<<endl<<"Phone:"<<member[ID].GetPhone()<<endl;
}
}
After executing these lines I get access violation error(for SetName function)
int _tmain(int argc, _TCHAR* argv[])
{
PhoneBook mem;
mem.AddNewContact("Bob","Jones","LA",100);
return 0;
}
However this code works fine!!! it means Set functions in Contact.h file work without any problems but after adding the Phonebook class it won't work.
int _tmain(int argc, _TCHAR* argv[])
{
PhoneBook mem;
Contact no("Bob","Jones","LA",100);
//mem.AddNewContact("Bob","Jones","LA",100);
return 0;
}
I will be grateful if you can help me.
Sorry for my mistake. I've forgotten to set a default value for ID variable.
Thanks Steve and Gray for your comments.
I was just experimenting and making my own string class. (Mainly because there is some stuff I wanted to build in custom methods like "toBase64" etc. Anyways, I was wondering how you could access the private member of char* when you use &String[0].
I thought you could use operator-overloading but I currently only have it as String[0] returns the char*. (I know & is the pointer operator).
String.h
namespace CoffeeBeans
{
class _declspec(dllexport) Coffee_String
{
char* String;
int StringLength;
public:
Coffee_String();
Coffee_String(LPCSTR CString);
LPSTR operator[](int);
~Coffee_String();
};
}
String.cpp
#include "stdafx.h"
#include "String.h"
#include <Windows.h>
CoffeeBeans::Coffee_String::Coffee_String() {
this->String = nullptr;
this->StringLength = 0;
}
CoffeeBeans::Coffee_String::~Coffee_String() {
if (String != nullptr) {
delete[] this->String;
this->String = nullptr;
this->StringLength = 0;
}
}
CoffeeBeans::Coffee_String::Coffee_String(LPCSTR CString) {
int StringLength = strlen(CString) + 1;
this->String = new char[StringLength]();
this->StringLength = StringLength - 1;
memcpy_s(this->String, StringLength, CString, StringLength);
}
LPSTR CoffeeBeans::Coffee_String::operator[](int)
{
return this->String;
}
Main.cpp
case WM_CREATE:{
CoffeeBeans::Coffee_String String("Test");
//I want to be able to do
//strcpy_s(&String[0], 3, "hi"); //Copy "hi" into the private variable char*String.
//I know this isn't a practical use, I wanted quick example (I would really pass it to recv (WinSock2))
MessageBeep(0);
break;
}
Your operator[] is returning the wrong value. In order for &String[index] to access the correct memory address, operator[] needs to return a reference to the character at the specified index, not return the string pointer itself, as you are currently doing.
If you look at the actual declaration of std::string::operator[], you will see that it returns a std::string::reference (aka char &) or std::string::const_reference (aka const char &) (depending on whether it is being called on a non-const or const std::string object).
Try something more like this:
String.h
namespace CoffeeBeans
{
class _declspec(dllexport) Coffee_String
{
char* String;
int StringLength;
public:
Coffee_String();
Coffee_String(const Coffee_String &src);
Coffee_String(const char *src);
~Coffee_String();
char& operator[](int index);
const char& operator[](int index) const;
Coffee_String& operator=(const Coffee_String &rhs);
};
};
String.cpp
#include "stdafx.h"
#include "String.h"
#include <algorithm>
#include <cstring>
CoffeeBeans::Coffee_String::Coffee_String() {
String = nullptr;
StringLength = 0;
}
CoffeeBeans::Coffee_String::Coffee_String(const CoffeeBeans::Coffee_String &src) {
StringLength = src.StringLength;
String = new char[StringLength+1];
std::copy(src.String, src.String+StringLength, String);
String[StringLength] = 0;
}
CoffeeBeans::Coffee_String::Coffee_String(const char *src) {
StringLength = std::strlen(str);
String = new char[StringLength+1];
std::copy(src, src+StringLength, String);
String[StringLength] = 0;
}
CoffeeBeans::Coffee_String::~Coffee_String() {
delete[] String;
String = nullptr;
StringLength = 0;
}
char& CoffeeBeans::Coffee_String::operator[](int index)
{
return String[index];
}
const char& CoffeeBeans::Coffee_String::operator[](int index) const
{
return String[index];
}
CoffeeBeans::Coffee_String& CoffeeBeans::Coffee_String::operator=(const CoffeeBeans::Coffee_String &rhs);
{
Coffee_String temp(rhs);
std::swap(String, temp.String);
std::swap(StringLength, temp.String);
return *this;
}
Main.cpp
case WM_CREATE: {
CoffeeBeans::Coffee_String String("Test");
strcpy_s(&String[0], 3, "hi"); //Copy "hi" into the private variable char *String...
// note that the content of String will become "hi\0t\0", not "hi\0"
// and StringLength will still be 4...
MessageBeep(0);
break;
}
I have the following code:
//test.cpp
#include <Physical_file.h>
#include <boost\python.hpp>
using namespace boost::python;
using namespace FMS_Physical;
BOOST_PYTHON_MODULE(python_bridge)
{
class_<Physical_file>("pf")
.def("pcreate", &Physical_file::pcreate)
;
}
//physical_file.h
#include <fstream>
#include "tools.h"
using namespace std;
#define FMS_lvl0_DLL_API __declspec(dllexport)
namespace FMS_Physical
{
const int BLOCK_OFFSET = 20 + 4;
const string SUFFIX(".hash");
struct block
{
unsigned int BlockNr;
char filler[20];
char data[1024 - BLOCK_OFFSET];
};
class Physical_file
{
public:
fstream filefl;
string workingDir;
string fileName;
int fileSize;
block currBlock;
block FHBuffer;
bool opened;
string openMode;
/************
functions
************/
FMS_lvl0_DLL_API Physical_file(void);
FMS_lvl0_DLL_API Physical_file(string &FileName, int FileSize, string &Dir = getCurrentPath());
FMS_lvl0_DLL_API Physical_file(string &FileName, string &Type, string &Dir = getCurrentPath());
FMS_lvl0_DLL_API ~Physical_file(void);
void FMS_lvl0_DLL_API pcreate(string &Name, int Size = 1000, string &Dir = getCurrentPath());
void FMS_lvl0_DLL_API pdelete(void);
void FMS_lvl0_DLL_API popen(string &name, string &OpenMode = string("I"), string &Dir = getCurrentPath());
void FMS_lvl0_DLL_API pclose(void);
void FMS_lvl0_DLL_API seekToBlock(unsigned int BlockNr);
void FMS_lvl0_DLL_API WriteBlock(void);
void FMS_lvl0_DLL_API ReadBlock(void);
void FMS_lvl0_DLL_API WriteFH(void);
void FMS_lvl0_DLL_API ReadFH(void);
};
}
//physical_file.cpp
void Physical_file::pcreate(string &Name, int Size, string &Dir)
{
if (Dir.compare("") == 0)
Dir = getCurrentPath();
string fileFullName = Dir + '\\' + Name + SUFFIX;
this->filefl.open(fileFullName.c_str(),ios::in | ios::binary);
if (filefl.is_open())
{
throw new exception((string("in function Physical_file::pcreate, file:") + fileFullName + " exists.").c_str());
}
try{
this->filefl.open(fileFullName.c_str(),ios::binary | ios::out);
this->opened = true;
this->seekToBlock(0);
this->currBlock.BlockNr = 0;
for (int i = 0; i < Size; i++)
{
for (int j = 0; j < sizeof(currBlock.data); j++)
this->currBlock.data[j] = 0;
for (int j = 0; j < sizeof(currBlock.filler); j++)
this->currBlock.filler[j] = 0;
this->WriteBlock();
}
this->pclose();
this->fileName = Name;
this->workingDir = Dir;
this->fileSize = Size;
}
catch(exception e)
{
throw new exception("in Physical_file::pcreate \n" + *e.what());
}
}
Physical_file::Physical_file(void)
{
this->fileName = string("");
this->workingDir = string("");
this->opened = false;
}
(there is some more code, I think its irrelevant to the problem)
when trying to compile I get the following error:
error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access private member declared in class 'std::basic_ios<_Elem,_Traits>'
can anyone explain why this problem happens and how to fix it?
(I'm compiling using vs2010, python27 and the c++ boost libs)
the files physical_file.cpp and physical_file.h are compiled to a dll used by test.cpp
By default, Boost.Python will automatically register to_python conversions for exposed types, such as Physical_file. As such, Boost.Python requires that these types be copyable. In this case, Physical_file is not copyable its filefl members is of a type that is not copyable: fstream.
To resolve this, either:
Determine copy/ownership semantics of filefl, and manage it through a holder object. For example, boost::shared_ptr.
Suppress automatic registration of python conversions by providing boost::noncopyable as a template argument when exposing the Physical_file class.
BOOST_PYTHON_MODULE(python_bridge)
{
boost::python::class_<Physical_file, boost::noncopyable>("pf")
.def("pcreate", &Physical_file::pcreate)
;
}
For more options when exposing a C++ class to Python, refer to the boost::python::class_ documentation.
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';
}