I've created an object and a Repository for it.
When I try inserting the object into the Repository (with the insert function i've created) I get compile error.
The Class I'm trying to insert into Repository
class Payment{
private:
int day;
int amount;
char *type;
public:
Payment();
Payment(int day, int amount, char *type);
Payment(const Payment &p);
~Payment();
//getters
int getDay()const;
int getAmount()const;
char* getType()const;
//setters
void setDay(int day);
void setAmount(int amount);
void setType(char* type);
//operator
Payment& operator=(const Payment& other);
friend ostream& operator<<(ostream &os,const Payment &obj);
};
//copy constructor
Payment::Payment(const Payment & p){
this->day = p.day;
this->amount = p.amount;
if(this->type!=NULL)
delete[] this->type;
this->type = new char[strlen(p.type)+1];
strcpy_s(this->type, strlen(p.type) + 1, p.type);
}
//assignment operator
Payment& Payment::operator=(const Payment &other) {
this->day = other.day;
this->amount = other.amount;
this->type = new char[strlen(other.type) + 1];
strcpy_s(this->type, strlen(other.type) + 1, other.type);
return *this;
}
//destructor
Payment::~Payment(){
this->day = 0;
this->amount = 0;
if (this->type != NULL) {
delete[]this -> type;
this->type = NULL;
}
}
//Repository header
class Repository{
private:
vector<Payment> list;
public:
Repository();
int getLength();
void insert(const Payment& obj);
void remove(int position);
};
//Repository cpp
Repository::Repository(){
this->list.reserve(10);
}
//return the size of the list
int Repository::getLength() {
return this->list.size();
}
//add payment to list
void Repository::insert(const Payment &obj) {
this->list.emplace_back(obj);
}
//remove payment from list
void Repository::remove(int position) {
this->list.erase(this->list.begin() + position);
}
In main function I have
char c[] = "some characters";
Payment pay = Payment(7,9,c);
Repository rep = Repository();
rep.insert(pay);
When I run the program I get the error "
Expression: _CrtlsValidHeapPointer(block) "
Since std::vector will make copies, a std::vector<Payment> requires that Payment has correct copy semantics. Your copy constructor and assignment operator are not implemented correctly. The assignment operator causes memory leaks, since you failed to delete [] the existing memory.
The easiest solution is to drop using the char *type; member and simply use std::string type;. Then the Payment class would have the correct copy semantics automatically.
Given that, the corrections to your Payment class is below:
#include <algorithm>
//...
Payment::Payment() : day(0), amount(0), type(nullptr) {}
Payment::Payment(const Payment & p) : day(p.day), amount(p.amount), type(nullptr)
{
if ( p.type )
{
type = new char[strlen(p.type) + 1];
strcpy_s(this->type, strlen(p.type) + 1, p.type);
}
}
// Use the copy/swap idiom
Payment& Payment::operator=(const Payment &other)
{
Payment temp(other); // make a temporary copy
// swap out contents of temporary with this object
std::swap(temp.day, day);
std::swap(temp.amount, amount);
std::swap(temp.type, type);
return *this;
} // when this brace has been reached, the temp copy dies off with the old data
Payment::~Payment()
{
delete [] type;
}
The above uses the copy/swap idiom within the assignment operator. The copy constructor uses a member initialization list.
The destructor need not check for a null pointer, since deleting a nullptr is perfectly valid.
Now adding to a std::vector is working well, without any runtime error (using the code #PaulMcKenzie posted). I've also found an example of code that's working, where only the assignment operator is kinda different.
Converted to my code would be (and it's working either):
Payment& Payment::operator=(const Payment &other) {
if (this != &other) {
this->setDay(other.day);
this->setAmount(other.amount);
this->setType(other.type);
}
return *this;
}
Thanks for the help! Now it's working perfectly! I didn't get to study very much from <algorithm> library, so I'll have to take a closer look. Wish you the best luck! ^_^
Related
I am new to the topic of overloading copy constructors and I just wanted someone to look at my code for my class and see if I am overloading my copy constructor correctly. It is only using a single string as user input. Also, do I need the '&' or not?
class TODO {
private:
string entry;
public:
List* listArray = nullptr;
int itemCount = 0, currInvItem = 0;
int maxLength = 22;
TODO() { entry = ""; };
TODO(const string& ent) { setEntry(ent); }; // Is this correct?
void setEntry(string ent) { entry = ent; };
string getEntry() const { return entry; };
void greeting();
void programMenu();
void newArray();
void getList();
void incList();
void delTask();
string timeID();
string SystemDate();
friend istream& operator >>(istream& in, TODO& inv);
friend ostream& operator <<(ostream& out, TODO& inv);
void componentTest();
void setTask(string a);
string getTask();
bool validTask(string a);
bool notEmpty(string e);
};
That's correct, but it's just a constructor of TODO taking a const reference to a string. You can test it here.
Passing const string& ent (by const reference) is not a bad idea. Another option would be to pass string ent (by value), and move that string when initializing entry, i.e. : entry{ std::move(ent) }. As here.
The class TODO has a default copy constructor. Check the line at the Insight window here (you'll have to click Play first).:
// inline TODO(const TODO &) noexcept(false) = default;
The default copy constructor would just copy the members, including the List pointer, but not the List elements (shallow copy). Notice both instances of TODO would be pointing to the same List elements, and any operation on them would affect both instances.
Should you want to implement a custom copy constructor, the syntax would be (see here):
TODO(const TODO& other) {
std::cout << "custom copy_ctor\n";
*this = other;
// Copy listArray elements
...
}
I've tried looking for a solution but the answers in those questions are very specific. Here's what I have.
The header Code.
class InventoryItem {
public:
InventoryItem(char *desc = 0, double c = 0, int u = 0);
~InventoryItem();
char *getDescription() const;
double getCost() const;
int getUnits() const;
void operator= (const InventoryItem &right);
int setUnits;
private:
char *description;
double cost;
int units;
};
The .cpp file associated with the header file.
InventoryItem::InventoryItem(char *desc, double c, int u) {
description = desc;
cost = c;
units = u;
}
InventoryItem::~InventoryItem() {}
void InventoryItem::operator= (const InventoryItem &right) {
units = right.getUnits();
cost = right.getCost();
description = right.getDescription();
}
The CashRegister class.
class CashRegister {
public:
void getItemToPurchase(InventoryItem) const;
private:
InventoryItem item;
}
The error occurs in this code, which is the .cpp file to the CashRegister function.
void CashRegister::getItemToPurchase(InventoryItem item1) const {
item = item1;
}
It says "No viable operator"=" even though item and item1 are both objects of the same class.
I've compared my code to the one in the book but it still doesn't work.
The problem is with const member function in CashRegister. In CashRegister::getItemOnPurchase(), item is a const member. Hence
item = item1;
is not a viable function.
I can think of couple of ways to solve the problem.
Return the object
InventoryItem CashRegister::getItemToPurchase() const {
return item;
}
Return the object as an output argument.
void CashRegister::getItemToPurchase(InventoryItem& item1) const {
item1 = item;
}
Also, it is more idiomatic to return a reference to the object in the operator= function.
InventoryItem& operator= (const InventoryItem &right);
I can´t get the code to be vieved here for some unknown reason so I post my code with JavaScript snippets. Can anybody help me straighten this code out? I really need it to work and I am stuck. How can I write it so it works? I did put my code into JavaScript snippets but it´s not working. It is C++ code and i need a vector in a class.
class Bank {
public:
Bank(int m_size): konton(m_size, 0) {}
unsigned int getSize() const { return konton.size(); }
Bank(const Bank& _konton,) : konton(_konton){}
Bank(const Bank &rhs) : konton(rhs.konton) {}
Bank operator=(const Bank &rhs)
{
if (&rhs == this)
{
return *this;
}
konton = rhs.konton;
return *this;
}
void SetInfo(const int _konton)
{
konton = _konton;
}
int Konton() const { return konton; }
private:
vector<Bank> konton;
};
#endif
I cleaned a bit your mess and changed a bit metods, hope you gonna understand. But first of all take a look at rule of three/five/zero, because this code is mostly about it. Down below I pointed out some important things. It's not perfect, but should be got place to start.
class Bank {
public:
//
// Default constructor
// You don't need to define size of vector
Bank(): konton() {}
// Copy constructor
Bank(const Bank& other)
: konton(vector<int> (other.konton)) {
}
// Copy assignment operator
Bank operator=(const Bank &rhs)
{
if (&rhs == this) return *this;
konton = rhs.konton;
return *this;
}
// You missing destructor ~Bank();
//
// Also you can add two more functions:
// - Move constructor Bank(const Bank&& other);
// - Move assignment operator Bank& operator=(Bank&& other);
// This just add new element at the end of konton
void addKonto(const int _konto)
{
konton.push_back(_konto);
}
// And this remove last
void removeKonto()
{
konton.pop_back();
}
// Getters
vector<int> getKonton() const { return konton; }
unsigned int getSize() const { return konton.size(); }
private:
// I guess you mean to store accounts numbers in the Bank class
// To make it simple I made it int but, it can by any other your specific data type
vector<int> konton;
};
PS. Consider using IDE with on-the-fly syntax checking.
Edit: Here you have some more about this.
I am trying to improve my understanding of the copy constructor and copy assign. operator
Here is a simple class that I came up with
class Bar
{
char* name;
int zip;
std::string address;
public:
Bar(const Bar& that)
{
//Copy constructor
size_t len = strlen(that.name + 1);
name = new char[len];
strcpy(name, that.name);
//Copy the zip
this->zip = that.zip;
//Copy the address
this->address = that.address;
}
Bar& operator=(const Bar& that)
{
//Assignment operator
if(this != &that)
{
//Copy the name
size_t len = strlen(that.name + 1);
name = new char[len];
strcpy(name, that.name);
//Copy the zip
this->zip = that.zip;
//Copy the address
this->address = that.address;
}
return *this;
}
};
My question is since the code in the copy constructor and copy assignment operator are the same does it make more sense to unify that into a deep copy method so that incase I add another member variable I dont have to add another line to the copy cnstr and copy assign. section ? Any suggestions ?
The "normal" way of doing things where you manage your own resources is a little different:
char* cppstrdup(const char*s, int len=0);
class Bar
{
char* name;
int zip;
std::string address;
public:
Bar(const Bar& that)
:name(nullptr),
zip(that->zip),
address(that->address)
{
name = cppstrdup(that.name); //done here for exception safety reasons
}
Bar(Bar&& that) //if you have C++11 then you'll want this too
:name(nullptr)
{
swap(*this,that);
}
~Bar() //you forgot the destructor
{
delete [] name;
}
Bar& operator=(Bar that) //this is called copy and swap.
{ //"that" is a copy (notice, no & above), and we simply swap
swap(*this,that);
return *this;
}
friend void swap(Bar& left, Bar& right)
{
using std::swap;
swap(left.name, right.name);
swap(left.zip, right.zip);
swap(left.address, right.address);
}
};
//uses new instead of malloc
inline char* cppstrdup(const char* s, int len)
{
if (s==0) return nullptr;
if (len==0) len = strlen(s);
char* r = new char[len+1];
strncpy(r, len+1, s);
r[len] = 0;
return r;
}
The benefits of this pattern is that it is much easier to get exception safety, often with the strong exception guarantee.
Of course, even more normal is to not use char* name, and obey the "Rule of Zero" isntead. In which case, it becomes VERY different:
class Bar
{
std::string name;
int zip;
std::string address;
public:
Bar() = default; //well, that's easy
};
Check COPY & SWAP idiom. In short - your logic goes into copy constructor and swap method and your assignment operator looks like:
Bar& operator=(const Bar& that)
{
Bar temp(that);
swap(*this, temp);
return *this;
}
I am working on a homework assignment for a C++ class, and having some difficulties. My program is segfaulting due to "use of uninitialised value of size 8" and "invalid read of size 8" in item::name() which is called by item::operator=.
#ifndef ITEM_H
#define ITEM_H
const double WEIGHT_DEFAULT = 1.0;
const int ITEM_NAME_LENGTH = 30;
class item {
public:
// Constructors and deconstructor
item();
item(char* nme, double weight);
virtual ~item();
// Copy constructor
item(const item& itm);
// Overload assignment operator
const item& operator=(const item& itm);
// Overload inequality operator
bool operator!=(const item&) const;
// Mutators and accessors
const char* name(void) const;
double weight(void) const;
void weight(double wght);
void name(char* nme);
protected:
private:
char* m_name;
double m_weight;
};
#endif // ITEM_H
Here is the portion of the implementation that I think is having issues:
...
const item& item::operator=(const item& itm)
{
if (strcmp(this->name(), itm.name()) != 0)
{
this->weight(itm.weight());
strcpy(m_name, itm.name());
}
return *this;
}
const char* item::name(void) const {
return m_name;
}
...
As you can see, part of the assignment is to use c-strings, thus I'm stuck with the messy details. My understanding of pointers and classes is that when working with both, we need to implement destructors, copy constructors, and overload the assignment operator. I've done all of the above. I looked at some info on the copy-and-swap idiom here on Stack Overflow, and tried implementing that, but couldn't get that to work with my code either.
My brain is getting frazzled trying to puzzle out where I went wrong. Could someone please tell me what I'm missing?
Thanks!
EDIT
Here are the constructors, destructor, and such:
item::item() {
//ctor
m_name = new char[ITEM_NAME_LENGTH];
strncpy(m_name, " ", ITEM_NAME_LENGTH - 1);
this->weight(WEIGHT_DEFAULT);
return;
}
item::item(char* nme, double wght) {
m_name = new char[ITEM_NAME_LENGTH];
strncpy(m_name, nme, ITEM_NAME_LENGTH - 1);
// We want to check for a rational value being
// passed in to weight. In theory, an item has
// to have *some* kind of weight, so we check
// for a weight of 0. If a weight of 0 has been passed in,
// we instead initialize the item's weight to the
// default weight (set in the header file).
if (wght > 0.0) {
this->weight(wght);
} else {
this->weight(WEIGHT_DEFAULT);
}
return;
}
item::~item() {
//dtor
// TODO: We need to clean up any variables here.
delete[] m_name;
}
item::item(const item& itm) {
// copy ctor
this->weight(itm.weight());
strncpy(m_name, itm.name(), ITEM_NAME_LENGTH - 1);
}
const item& item::operator=(const item& itm)
{
if (strcmp(this->name(), itm.name()) != 0)
{
this->weight(itm.weight());
strcpy(m_name, itm.name());
}
return *this;
}
bool item::operator!=(const item& itm) const
{
return (strcmp(m_name, itm.name()) != 0);
}
EDIT 2
Now that I've stopped trying to dynamically allocate the name c-string, I'm getting memory errors on the weight function...
double item::weight(void) const {
return m_weight;
}
void item::weight(double wght)
{
m_weight = wght;
}
First off, you don't need to explicitly return; from void statements.
Second:
When creating a copy constructor, you need to allocate the space that will be used to hold the memory of that constructor, the same way you do for the regular constructor.
Try this in your copy constructor:
m_name = new char[ITEM_NAME_LENGTH];
Edit: for completeness this is what my "appears to be working" code is:
#include <stdio.h>
#include <string.h>
const double WEIGHT_DEFAULT = 1.0;
const int ITEM_NAME_LENGTH = 30;
class item {
public:
// Constructors and deconstructor
item();
item(char* nme, double weight);
virtual ~item();
// Copy constructor
item(const item& itm);
// Overload assignment operator
const item& operator=(const item& itm);
// Overload inequality operator
bool operator!=(const item&) const;
// Mutators and accessors
const char* name(void) const;
double weight(void) const;
void weight(double wght);
void name(char* nme);
protected:
private:
char* m_name;
double m_weight;
};
const item& item::operator=(const item& itm)
{
if (strcmp(this->name(), itm.name()) != 0)
{
m_name = new char[ITEM_NAME_LENGTH];
this->weight(itm.weight());
strcpy(m_name, itm.name());
}
return *this;
}
const char* item::name(void) const {
return m_name;
}
double item::weight(void) const {
return m_weight;
}
void item::weight(double wght) {
m_weight = wght;
}
item::item() {
//ctor
m_name = new char[ITEM_NAME_LENGTH];
strncpy(m_name, " ", ITEM_NAME_LENGTH - 1);
this->weight(WEIGHT_DEFAULT);
return;
}
item::item(char* nme, double wght) {
m_name = new char[ITEM_NAME_LENGTH];
strncpy(m_name, nme, ITEM_NAME_LENGTH - 1);
// We want to check for a rational value being
// passed in to weight. In theory, an item has
// to have *some* kind of weight, so we check
// for a weight of 0. If a weight of 0 has been passed in,
// we instead initialize the item's weight to the
// default weight (set in the header file).
if (wght > 0.0) {
this->weight(wght);
} else {
this->weight(WEIGHT_DEFAULT);
}
return;
}
item::~item() {
//dtor
// TODO: We need to clean up any variables here.
delete[] m_name;
}
item::item(const item& itm) {
// copy ctor
this->weight(itm.weight());
m_name = new char[ITEM_NAME_LENGTH];
strncpy(m_name, itm.name(), ITEM_NAME_LENGTH - 1);
}
bool item::operator!=(const item& itm) const
{
return (strcmp(m_name, itm.name()) != 0);
}
int main(int argc, char* argv[])
{
item i("test",2.0);
item b = i;
item c;
item d = c;
return 0;
}
I guess using std::string is out as part of the exercise, right? Otherwise, that's the way to go for string handling. Another thing you could try is to avoid the dynamic allocation of the string. Instead, just use a char m_name[ITEM_NAME_LENGTH];. BTW: Which length is that? If it's the maximum number of characters in the name, you need a +1 for the terminating NUL.
That said, one more thing: In assignment operators, you compare if(this != &other), i.e. you compare the address of the two objects. The point is to avoid self-assignment, which is error-prone. Your assignment checks if the names are different and only then copies the names and the weight. What if only the weight was different?