C++ Why didn't the default copy work? [duplicate] - c++

This question already has answers here:
Why does the C++ map type argument require an empty constructor when using []?
(6 answers)
Closed 5 years ago.
I've done a lot of Googling and can't seem to figure out what's going on. I'm teaching myself C++ (I'm more familiar with Java).
I have Item Class objects that are being stored in an Inventory Class map, not as pointers. I want to retrieve one of the items from the Inventory in a function, assign it to a temp variable while I delete it from the Inventory map, and then return the object itself so something else can use it. When I originally tried using the code within my function it was returning the error (followed by the stack trace of c++ library stuff):
no matching constructor for initialization of 'Item'
::new ((void*)__p) _Tp();
I tried creating a copy constructor, but to no avail. Eventually, it worked by including an empty constructor ( Item(); ) in my header file and defining it in my cpp file ( Item::Item() {} ).
I would just like to understand why this was necessary so I can recognize it in the future to know what I'm doing.
EDIT: Upon further inspection of the error stack trace, it turned out the actual problem with with the Inventory::addItem function. When assigning an object to a map using operator[], the map first instantiates the value type to the key using the default constructor before making the assignment. No default constructor was available, so the error was returned.
It was fixed by changing the line to map.insert({key, value})
Here are the important parts of the two class files:
//item.h
#include <string>
using namespace std;
class Item {
private:
string name;
int type;
int levelReq;
public:
Item(string name, int type, int levelReq);
Item();
string getName() {return name;}
int getType() {return type;}
friend ostream &operator<<(ostream &out, const Item &item);
};
---------------------------------------------------------------
//item.cpp
#include <string>
#include "item.h"
using namespace std;
Item::Item(string n, int t, int l) : name(n), type(t), levelReq(l) {}
Item::Item() {}
ostream &operator<<(ostream &out, const Item &item) {
return out << item.name;
}
---------------------------------------------------------------
//inventory.h
#include <map>
#include "item.h"
class Inventory {
private:
map <int, Item> inventory;
int size;
bool full;
int nextFree;
void findNextFree();
public:
Inventory();
bool isFull() {return full;}
void addItem(Item item);
Item getItem(int slot);
void showInv();
};
---------------------------------------------------------------
//inventory.cpp
#include <iostream>
#include <string>
#include "inventory.h"
#include "item.h"
using namespace std;
Inventory::Inventory() {
full = false;
nextFree = 1;
size = 28;
}
void Inventory::addItem(Item item) {
if (!full) {
inventory[nextFree] = item;
findNextFree();
}
else {
cout << "Your inventory is full (Inv::addItem)";
}
}
Item Inventory::getItem(int slot) {
Item item = inventory.at(slot);
inventory.erase(slot);
full = false;
if (nextFree > slot) {
nextFree = slot;
}
return item;
}
void Inventory::findNextFree() {
nextFree++;
if (nextFree == size + 1) {
full = true;
}
else if (inventory.count(nextFree)) {
findNextFree();
}
}

I think the issue rose because you declared a constructor for your item class.
C++ will automatically generate the necessary constructors if you don't provide any custom constructors.
The necessary constructors are the default, copy and move constructors.
The moment you provide one, the default constructors won't be generated and you have this issue. This principle will also apply to structs.
Check the reference to see for yourself:
http://en.cppreference.com/w/cpp/language/default_constructor
http://en.cppreference.com/w/cpp/language/copy_constructor
http://en.cppreference.com/w/cpp/language/move_constructor
Hope this answers your question.

Related

Why is my class constructor being called twice?

I've got a base class Container with a derived class Player_Inventory. There can only be one Player_Inventory so my code throws an exception if for some reason a second one is created.
The problem I'm having is that my code is failing my test as it throws the exception even on what is supposed to be the very first construction of the Player_Inventory class. I've debugged the code and two things are happening which I don't quite understand - the number attribute is not tracked by the debugger (at least not in the GUI on VSC), and it seems that right after hitting the first REQUIRE statement, the constructor is called again, thus triggering the exception.
Can anyone help?
After rewriting my constructor method, I'm still getting a similar error.
My revised code is as follows:
containers.h
#include<iostream>
#include<string>
#include<vector>
class Item { // Placeholder class for items
public:
std::string name;
Item(std::string n) : name{n} {};
};
class Container {
protected:
std::string name;
std::string description;
std::vector<Item> contents;
public:
Container(std::string, std::string);
std::string get_name() {return name;}
std::string get_description() {return description;}
std::vector<Item> get_contents() {return contents;}
};
containers.cpp (there are more methods defined in this file which aren't used here)
#include<iostream>
#include<string>
#include "containers.h"
Container::Container(std::string n, std::string desc) : name{n}, description{desc} {};
player_inventory.h
#include "containers.h"
class Player_Inventory : public Container {
public:
static int number;
Player_Inventory(std::string, std::string);
};
player_inventory.cpp
#include<iostream>
#include<stdexcept>
#include "player_inventory.h"
Player_Inventory::Player_Inventory(std::string n, std::string desc): Container(n, desc) {
number += 1;
if (number > 1){
throw std::invalid_argument("You can only have one inventory!");
}
};
int Player_Inventory::number = 0;
test_file.cpp
#include "../lib/Catch2/catch.hpp"
#include "player_inventory.h"
#include<iostream>
#include<string>
#include<vector>
SCENARIO("A player can have an inventory.") {
WHEN("A player inventory is created.") {
Player_Inventory myInventory("My Inventory", "Inventory for the player");
THEN("The created inventory has the correct attribute values.") {
REQUIRE(myInventory.get_name() == "My Inventory");
REQUIRE(myInventory.get_description() == "Inventory for the player");
REQUIRE(myInventory.get_contents().empty());
} // The code works fine when only up to here is included
AND_THEN("Only one player inventory can exist.") { // as soon as this line is included it tries to create another player_inventory object, causing the fail
REQUIRE_THROWS((Player_Inventory myOtherInventory("Second Inventory", "Testing for another one"))); // These two lines were not included but I've included them here as this is the test I wanted to run
REQUIRE(myInventory.get_number() == 1);
}
}
}
Not sure if related, but that's how you should call the Base constructor:
Player_Inventory(std::string n, std::string desc) : Container(n, desc) {
}

Can we dynamically insert operations to our function?

In this thread link, concerns the discussion on real example of using the strategy design pattern. The second answer which shows an example of dynamically inserting rules to whether approve/decline the assignment of products to people with the RuleAgent. This set of rules is invoked using the function IsApproved.
The example shows what if we wanted to add two more rules, like an intern rule and overtime rule. My question relates to how do we ensure that our polymorphic call to IsApproved would call ALL the added rules. The question has also been asked in the comment to that answer but no replies.
Could you please comment on how to do this on C++ and/or (if possible) Fortran.
This example sidesteps polymorphism, where the agent is a vector of function pointers that can be dynamically added to and removed from :
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
class Person
{
public:
int _timesheet = 50;
std::string _title = "Intern";
};
class Assignment
{
public:
Person _person;
};
namespace OvertimeRule
{
bool IsApproved(Assignment const& assignment)
{
return assignment._person._timesheet >= 40;
}
}
namespace InternRule
{
bool IsApproved(Assignment const& assignment)
{
return assignment._person._title == "Intern";
}
}
int main()
{
Assignment testAssignment;
std::vector<bool(*)(Assignment const&)> assignmentAgent;
assignmentAgent.push_back(&OvertimeRule::IsApproved);
assignmentAgent.push_back(&InternRule::IsApproved);
bool const testSuccess = std::all_of(assignmentAgent.begin(), assignmentAgent.end(),
[&testAssignment] (auto const& Func)
{
return Func(testAssignment);
});
if(testSuccess)
{
std::cout << "Requirements Met!";
}
else
{
std::cout << "Requirements Not Met!";
}
}

A function that returns a queue?

I'm trying to figure out how queues work in C++ and am getting stuck when dealing with objects. I seem to only be able to get a return address instead of the name of the object (which is what I really want). It's also showing an error when I try to pop the element from the queue. My code is as follows:
Buyer.h file
#ifndef BUYER_H
#define BUYER_H
#include <string>
#include <queue>
#include "Order.h"
#include "Entity.h"
#include "Seller.h"
class Order;
class Seller;
class Buyer : public Entity {
public:
Buyer(const std::string &, const std::string &, double);
virtual ~Buyer() { }; // when step is added make this virtual
void addSeller(Seller *);
std::queue<Seller*> getSellers() const;
void addOrder(Order *);
std::queue<Order*> getOrders() const;
virtual void list() const override;
virtual void step() const override;
private:
std::queue<Order*> orders;
std::queue<Seller*> sellers;
};
#endif
Buyer.cpp file
#include <iostream>
#include <ostream>
#include <stdexcept>
#include <string>
#include <queue>
#include "Buyer.h"
#include "Seller.h"
#include "Order.h"
#include "Entity.h"
using namespace std;
Buyer::Buyer(const std::string &name, const std::string &id, double balance)
: Entity(name, id, balance)
{
// initialize seller and order queue??
} // Constructor
void Buyer::addSeller(Seller *s) {
sellers.push(s);
} // addSeller
std::queue<Seller*> Buyer::getSellers() const {
while(!sellers.empty()) {
return sellers;
} // while
} // getSellers
void Buyer::addOrder(Order *o) {
orders.push(o);
} // addOrder
std::queue<Order*> Buyer::getOrders() const {
while(!orders.empty()) {
return orders;
} // while
} // getOrders
void Buyer::list() const {
Entity::list();
std::cout << "Orders:\nOrder contains:";
std::cout << "\nSellers:\n";
int i = 0;
while(!sellers.empty()) {
std::cout << sellers.front() << "\n";
sellers.pop();
} // while
} //list
void Buyer::step() const {
std::cout << "\nstep enter\n"
<< "step exit\n\n";
} // step
Any help is appreciated! Thank you!
(This isn't a full answer but it is too big to go in a comment)
It's OK to return std::queue<Order *>, and so on. However, you need to be clear on who owns the objects being pointed to; i.e. who is responsible for deleting them.
When you return a std::queue<Order *>, what happens is that the returned queue is a copy of the original one, however all the pointers point to the same object that the original one pointed to . (This is a sort of "shallow copy").
If you then delete anything in the returned queue, you will cause the original queue to malfunction because it will be accessing deleted memory.
As such, this is a fragile design because the caller can easily cause the object to screw up despite the fact that getOrders is a const function.
One "solution" is to make the containers contain shared_ptr<Order> instead of Order *. Then everything happens automatically; the caller can add or delete to his heart's content.
If it is not strictly necessary for the containers to contain pointers, consider using containers of objects: std::queue<Order>. The benefit of this approach is that the default copy and move semantics are all correct.
Another approach to consider is having getOrders() and getSellers() return a const reference, instead of returning a copy of the queue.
NB. In Buyer::getSellers(), and getOrders() if it is empty then you fall off the end of the function without returning, causing undefined behaviour. You need to either return something (what's wrong with returning an empty queue?) or throw an exception.

Confused About Member Access Train in Class?

I have the following class:
#include <string>
#include <cstdlib>
using namespace std;
class Locker{
public:
int lockerId;
string renterName;
double monthlyRent;
// The variable is true when the locker is a vip locker
//if the locker is a regular locker then this variable is set to false
bool isVip;
bool isRentOverdue;
Locker(){};
Locker(int id, string name, double rent, bool vip=0, bool overdue=0);
bool operator==(Locker const &other);
};
EDIT: LOCKER NODE CLASS
class LockerNode{
public:
Locker objLocker;
LockerNode *next;
LockerNode(){
next=0;
};
LockerNode(Locker e, LockerNode *ptr=0){
objLocker=e;
next=ptr;
}
};
and implementation:
#include <sstream>
#include "Locker.h"
#include <iostream>
using namespace std;
Locker::Locker(int id, string name, double rent, bool vip, bool overdue){
lockerId=id; renterName=name; monthlyRent=rent; isVip=vip; isRentOverdue=overdue;
}
bool Locker::operator==(Locker const &other){
if(lockerId==other.lockerId && renterName==other.renterName && monthlyRent==other.monthlyRent && isVip==other.isVip && isRentOverdue==other.isRentOverdue)
return true;
else return false;
}
I have the following code in a function, trying to track both the number of objects in a linked list, and perform some operations on them based on how many their are and their properties. I am passing in e which is a newly created object. If an object has property vip = true, I need to place it ahead of other non-vip objects, unless there is already a vip object, in which case it goes just behind it. Hence, the following code:
int count = 0;
LockerNode *p = head;
for(;p!=0;count++, p=p->next) {
if(count == 1) {
if (e.isVip) {
if(p->isVip) // !!!!!!!!!Issue here!!!!!!!!!!
}
}
I checked the parameter fine to determine if it is vip or not. However, I am unsure how to check the current element I am at in the list for the same. My above effort on the line in question has not worked. I'm a little confused as to the syntax. Can anyone help me out?
Thanks!
where is your locker Node class? problem could be there...
ok try replacing this :
if(p->isVip) // !!!!!!!!!Issue here!!!!!!!!!!
with:
if (p->objLocker.isVip) {//true/false for this node
p is a pointer accesing his members is with->
but objlocker is not a pointer accesing his members is with a "."

No Matching Function Call

I'm new to C++ and trying to code a HashTable data structure.
I've written it to be generic using templates, and I've included a HashEntry object to use in it to allow for easy quadratic probing for collisions.
The code I have is:
(in a .C file that #include's the below class definition .H file):
HashEntry::HashEntry()
{
this->isActive = false;
}
And the associated .H file with the class definitions is:
#include <iostream>
#include <string>
#include "Entry.C"
using namespace std;
#define Default_Size 50000
class HashEntry;
template <class T> class HashTable
{
private:
int size;
int occupied;
T array[Default_Size];
public:
HashTable();
int Size();
void Add(T t);
void DebugAdd(T t, int index);
T* Get(string index);
/* How do I declare the existence of HashEntry BEFORE here? */
int FindNextOpen(HashEntry he); // Only works for hash_entry objects!
int Hash(string str);
void Rehash();
};
class HashEntry
{
private:
Entry e;
bool isActive;
public:
HashEntry();
HashEntry(Entry e);
bool IsActive();
Entry GetEntry();
};
Whenever I try and compile everything, I get the error for the HashEntry constructor above:
"no matching function for call to Entry::Entry()" ... "candidates are.....".
I have no idea what it means -- when I try to include a default Entry() constructor (my first interpretation), it throws more errors.
Thanks for the help!
UPDATE -- ENTRY.C:
#include "Entry.H"
/* ***Entry Methods*** */
/*
* Overloaded Entry obejct constructor that provides a string value.
*/
Entry::Entry(string s)
{
this->value = s;
this->count = 0;
}
/*
* Returns the number of times this Entry has been accessed/
* found.
*/
int Entry::Count()
{ return this->count; }
/*
* Returns the string value stored in the Entry object.
*/
string Entry::Value()
{ return this->value; }
And the associated .H file with the class definitions is:
#include <iostream>
#include <string>
#include "Entry.C"
Whoa! Never, ever #include a source file in a header.
Your Entry.C should not exist. Instead define the constructor in your header, inside the class definition:
class HashEntry
{
private:
Entry e;
bool isActive;
public:
HashEntry() : isActive(true) {}
...
}
One thing that you haven't shown us is the definition of the class Entry. That is one of the sources of your problem. It's a bit hard to pin down your problem when you didn't show us the very thing that is causing it.
I found the problem.
The error message says there is not matching function call for "Entry::Entry()". Because in no case was I actually creating Entry objects I had no idea what it meant.
I tried adding an explicit default constructor for class Entry and it resolved.
Thanks for the help everyone!