Copying pointers to objects with tables - c++

I have a problem when copying pointers to objects that contain tables... Some information is kept (strings, for example skillName), but the tables contain new, random data. I tried several things, but I still don't know what's wrong and how to do it... Help me, please. :)
EDIT: I've edited whole post, and as WhozCraig suggested made it MCVE (at least I tried).
Everything now is in this block of code, so you can just copy it and see it for yourself. For some reason the problem is in different location now, but it's still the same...
#include <iostream>
#include <string>
using namespace std;
class Skill
{
protected:
int const maxSkillLevel;
short skillLevel;
string skillName;
public:
Skill(string skillName) : maxSkillLevel(5){
skillLevel = 0;
this->skillName = skillName;
}
virtual ~Skill(){}
virtual int getMaxDmg(int i){ return 0; };
void increaseSkillLevel(int);
string getSkillName(){ return skillName; }
};
class OffensiveSkill : public Skill{
protected:
int *maxDmg;
public:
OffensiveSkill(string skillName, int maxDmg[]) : Skill(skillName){
this->maxDmg = maxDmg;
}
~OffensiveSkill(){}
int getMaxDmg(int i){ return maxDmg[i]; }
};
class Role{
protected:
string roleName;
Skill **skills;
public:
Role(string roleName){
skills = new Skill*[3];
this->roleName = roleName;
}
Role(Role* role){
this->skills = role->getSkills();
this->roleName = role->getRoleName();
}
Skill **getSkills(){ return skills; }
string getRoleName(){ return roleName; }
void setSkills(Skill* s1){ skills[0] = s1; }
};
class RoleGenerator{
protected:
Role *role;
public:
RoleGenerator(){
role = new Role("assassin");
int maxDmg[5] = { 30, 45, 60, 75, 90 };
OffensiveSkill* assassinate = new OffensiveSkill("Assassinate", maxDmg);
role->setSkills(assassinate);
cout << "maxDmg in RoleGenerator " << role->getSkills()[0]->getMaxDmg(0) << endl;
}
Role *getRoles(){ return role; }
};
int main(){
RoleGenerator* rg = new RoleGenerator();
Role *role = rg->getRoles();
cout << "maxDmg in main " << role->getSkills()[0]->getMaxDmg(0) << endl;
Role *copied = new Role(role);
//maxDmg here is different
cout << "maxDmg in after copying " << role->getSkills()[0]->getMaxDmg(0) << endl;
//but skill name is copied correctly
cout << "skill name " << role->getSkills()[0]->getSkillName() << endl;
}

The local array in RoleGenerator:: RoleGenerator()
int maxDmg[5] = { 30, 45, 60, 75, 90 };
is being passed as-address to:
OffensiveSkill* assassinate = new OffensiveSkill("Assassinate", maxDmg);
where that address is saved via:
this->maxDmg = maxDmg;
After RoleGenerator:: RoleGenerator() returns maxDmg is no longer valid to address. Dereferencing the saved address later invokes undefined behavior.
If a copy is sufficient one way to make this trivial is by copying the array into a simple member array or vector. There are multiple ways to do this. A decent arbitrary-length solution using a vector would be something like this:
#include <vector>
class OffensiveSkill : public Skill {
protected:
std::vector<int> maxDmg;
public:
template<size_t N>
OffensiveSkill(string skillName, int (&dmg)[N])
: Skill(skillName)
, maxDmg(dmg, dmg+N)
{
}
int getMaxDmg(int i) const { return maxDmg[i]; }
};
That alone should work as a drop-in replacement for your exiting constructor and class definition. If needed you can offer up additional flexibility by providing alternate constructors, such as one that allows beginning and end iterators directly passable to maxDmg construction, an int* and size_t length, etc.
And I would suggest you modify your indexing member getMaxDmg() to (a) range check the input value and toss an exception if out of range, and (b) use an unsigned data type (such as std::size_t) for your indexes. Unrelated to your question, but worth considering.

This is looking strange:
skills[0] = static_cast<OffensiveSkill*>(roleSkills[0]);
You would need to include more of your code.
But, based on the limited information, looks like you are better off with a copy constructor that is custom. A compiler generated copy-constructor won't perform deep-copy for you.

Related

Difficulty understanding c++ polymorphism

What I am trying to achieve is creating a superclass array of subclass objects.
In this particular test I'm working on, I want to have an animal array that has some dog objs and some cat objs while they maintain their attributes.
#include <iostream>
using namespace std;
//ANIMAL
class animal
{
protected:
int ID;
string name;
public:
animal(string = "Unknown");
int get_ID() { return ID; }
virtual string get_name() { return name; }
};
animal::animal(string n) { name = n; }
//DOG
class dog : public animal
{
static int newID;
string sound;
public:
dog(string = "Corgi", string = "Woof!");
string get_name() { return sound + " " + name; }
};
int dog::newID = 0;
dog::dog(string n, string s) : animal(n)
{
newID++;
ID = newID;
cout << ID << "\t";
sound = s;
}
//CAT
class cat : public animal
{
static int meowID;
string color;
public:
cat(string = "Munchkin", string = "Calico");
string get_name() { return color + " " + name; }
};
int cat::meowID = 89;
cat::cat(string n, string c) : animal(n)
{
meowID++;
ID = meowID;
cout << ID << "\t";
color = c;
}
//MAIN
int main(int argc, char* argv[])
{
animal** test;
animal* p;
for (int i = 0; i < 6; i++)
{
p = new dog;
p++;
}
cout << "\n";
for (int i = 0; i < 6; i++)
{
p = new cat;
p++;
}
cout << "\n";
test = &p;
cout << (*test-7)->get_ID();
return 0;
}
What I've learned so far is that p isn't an array, and it keeps pointing to different memory addresses through the loops.
I cannot do animal** test = new dog[6]; as it is an invalid initialization. Even if that worked I would have trouble cascading another array segment of cat.
This is the output I obtained:
1 2 3 4 5 6
90 91 92 93 94 95
0
The first line is displaying dog IDs being invoked 6 times, and the second line is displaying cat IDs being invoked 6 times. (*test-7)->get_ID();is the last number.
It seems the constructors are being invoked right. However, I have no idea where my pointer is pointing, since I am expecting 91 not 0.
How do I get an animal array that I can access information from each element? For example,
animal** myArray;
{do something}
cout << myArray[2].get_name() << endl << myArray[7].get_ID();
and it outputs
Woof! Corgi
91
One important detail about the animal class: polymorphic types can run into issues when their destructors are called but those destructors are not virtual. It is recommended that you make the destructor of the base class virtual, even if that class itself does not actually need a destructor. In this case, you can tell the compiler that you want the destructor to be virtual but generate a default implementation of it with:
virtual ~animal() = default;
Add the above line in the public: section of your animal class. This ensures that any derived classes that you define later on will get a virtual destructor automatically.
Now to the rest of your code:
p = new dog;
So far, so good. But then this:
p++;
does nothing useful other than making the pointer point to an invalid address. Then in the next iteration, another p = new dog; will be performed. The previous dog object you allocated is now lost forever. You got a so-called "leak".
It seems you expect new to allocate objects an a way that lays them out in memory one after another. That is not the case. new will allocate memory in an unpredictable location. As a result, this:
*test-7
cannot possibly work, as the objects are not laid out in memory the way you expected. What you get instead is an address to some memory location 7 "positions" before the latest allocated object that pretty much certainly does not point to the animal object you were hoping. And when you later dereference that you get undefined behavior. Once that happens, you cannot reason about the results anymore. They can be anything, from seeing wrong text being printed to your program crashing.
If you want an array of animal pointers, you should specifically create one:
animal* animals[12];
This creates an array named animals that contains 12 animal pointers. You can then initialize those pointers:
for (int i = 0; i < 6; i++) {
animals[i] = new dog;
}
cout << "\n";
for (int i = 6; i < 12; i++) {
animals[i] = new cat;
}
You then just specify the array index of the one you want to access:
cout << animals[0]->get_ID() << '\n'; // first animal
cout << animals[6]->get_ID() << '\n'; // seventh animal
Don't forget to delete the objects after you're done with the array. Since animals is an array, you can use a ranged for loop to delete all objects in it:
for (auto* animal_obj : animals) {
delete animal_obj;
}
However, all this low-level code is quite tedious and error-prone. It's recommended to instead use library facilities that do the allocations and cleanup for you, like std::unique_ptr in this case. As a first step, you can replace your raw animal* pointer with an std::unique_ptr<animal>:
unique_ptr<animal> animals[12];
(Don't forget to #include <memory> in your source file, since std::unique_ptr is provided by that library header.)
Now you've got an array of smart pointers instead of raw pointers. You can initialize that array with:
for (int i = 0; i < 6; i++) {
animals[i] = make_unique<dog>();
}
cout << "\n";
for (int i = 6; i < 12; i++) {
animals[i] = make_unique<cat>();
}
Now you don't need to delete anything. The smart pointer will do that automatically for you once it goes out of scope (which in this case means once the animals array goes out of scope, which happens when your main() function exits.)
As a second step, you can replace the animals array with an std::vector or an std::array. Which one you choose depends on whether or not you want your array to be able to grow or shrink later on. If you only ever need exactly 12 objects in the array, then std::array will do:
array<unique_ptr<animal>, 12> animals;
(You need to #include <array>.)
Nothing else changes. The for loops stay the same.
std::array is a better choice than a plain array (also known as "built-in array") because it provides a .size() member function that tells you the amount of elements the array can hold. So you don't have to keep track of the number 12 manually. Also, an std::array will not decay to a pointer, like a plain array will do, when you pass it to functions that take an animal* as a parameter. This prevents some common coding bugs. If you wanted to actually get an animal* pointer from an std::array, you can use its .data() member function, which returns a pointer to the first element of the array.
If you want the array to be able to grow or shrink at runtime, rather than have a fixed size that is set at compile time, then you can use an std::vector instead:
vector<unique_ptr<animal>> animals;
(You need to #include <vector>.)
This creates an empty vector that can store elements of type unique_ptr<animal>. To actually add elements to it, you use the .push_back() function of std::vector:
// Add 6 dogs.
for (int i = 0; i < 6; i++) {
animals.push_back(make_unique<dog>());
}
// Add 6 cats.
for (int i = 0; i < 6; i++) {
animals.push_back(make_unique<cat>());
}
Instead of push_back() you can use emplace_back() as an optimization, but in this case it doesn't matter much. They key point to keep in mind here is that a vector will automatically grow once you push elements into it. It will do this automatically without you having to manually allocate new elements. This makes writing code easier and less error-prone.
Once the vector goes out of scope (here, when main() returns,) the vector will automatically delete the memory it has allocated to store the elements, and since those elements are smart pointers, they in turn will automatically delete the animal objects they point to.
If you're new to C++, it's important that you get started on the right foot and to follow modern best practices, namely:
Avoid using pointers, new, delete, new[] and delete[].
Instead use smart-pointers (unique_ptr, shared_ptr, but don't use auto_ptr!).
Use the make_ functions instead of new. That way you don't need to worry about delete.
See Advantages of using std::make_unique over new operator
Use std::vector<T> (and std::array<T,N> if you have fixed-size collections) instead of new[] or p** (and never use malloc or calloc directly in C++!)
I note that you should also generally prefer Composition over Inheritance, but with trivial examples like yours it's difficult to demonstrate the concept because a Dog and a Cat "are" Animals.
I also note that when the possible set of subclasses is known at compile-time you should consider using a union-type instead of subclassing because it allows consumers to exhaustively work with returned values without needing to use RTTI or guesswork.
This can be done with using AnAnimal = std::variant<cat,dog>.
Anyway, this is what I came-up with. The class animal, class dog, and class cat code is identical to your posted code (and is located within the // #region comments), but the #include and using statements at the top are different, as is the main method.
Note that my code assumes you have a compiler that complies to the C++14 language spec and STL. Your compiler may default to C++11 or older. The std::make_unique and std::move functions require C++14.
Like so:
#include <iostream>
#include <memory>
#include <vector>
#include <string>
// Containers:
using std::vector;
using std::string;
// Smart pointers:
using std::unique_ptr;
using std::move;
using std::make_unique;
// IO:
using std::cout;
using std::endl;
// #region Original classes
//ANIMAL
class animal
{
protected:
int ID;
string name;
public:
animal(string = "Unknown");
int get_ID() { return ID; }
virtual string get_name() { return name; }
};
animal::animal(string n) { name = n; }
//DOG
class dog : public animal
{
static int newID;
string sound;
public:
dog(string = "Corgi", string = "Woof!");
string get_name() { return sound + " " + name; }
};
int dog::newID = 0;
dog::dog(string n, string s) : animal(n)
{
newID++;
ID = newID;
cout << ID << "\t";
sound = s;
}
//CAT
class cat : public animal
{
static int meowID;
string color;
public:
cat(string = "Munchkin", string = "Calico");
string get_name() { return color + " " + name; }
};
int cat::meowID = 89;
cat::cat(string n, string c) : animal(n)
{
meowID++;
ID = meowID;
cout << ID << "\t";
color = c;
}
// #endregion
int main()
{
// See https://stackoverflow.com/questions/44434706/unique-pointer-to-vector-and-polymorphism
vector<unique_ptr<animal>> menagerie;
// Add 6 dogs:
for( int i = 0; i < 6; i++ ) {
menagerie.emplace_back( make_unique<dog>() );
}
// Add 6 cats:
for( int i = 0; i < 6; i++ ) {
menagerie.emplace_back( make_unique<cat>() );
}
// Dump:
for ( auto &animal : menagerie ) {
cout << "Id: " << animal->get_ID() << ", Name: \"" << animal->get_name() << "\"" << endl;
}
return 0;
}

Constructor not getting called

I am making an array of 4 std::list. But when I try to access the array's first list's first A object and call the callMe() method on it I get a weird output.
Now 2 things could have happened:
Either the list was empty.
An A object was created when I tried to access the first element of the first list((*(arrayOflistOfA[0].begin()))).
Details of the above cases:
If no A object was created then I should have got an exception. But I didn't get any exception so I am assuming that an A object was created.
So if an A object was indeed created, then the constructor should have been called.
What am I missing?
#include <iostream>
using namespace std;
class A {
public:
A() {
cout<<"Constructor called"<<endl;
x=20;
}
void callMe();
private:
int x;
};
void A::callMe() {
cout<<"Value of x = "<<x<<endl;
}
int main() {
const int size = 4;
list<A>* arrayOflistOfA = new list<A>[size];
(*(arrayOflistOfA[0].begin())).callMe();
}
The output is:
Value of x = 0
but the output should have been:
Constructor called
Value of x = 20
If no A object was created then I should have got an exception.
Not true.
But I didn't get any exception so I am assuming that an A object was created.
Don't assume. Find out. Go to some documentation for begin() and for iterators and discover that you do not get an exception, you get UB.
An A object was created when I tried to access the first element of the first list((*(arrayOflistOfA[0].begin()))). [And] if an A object was indeed created, then the constructor should have been called.
That's right. Clearly you have no elements in the list.
And we know that, because there is no code in your program that adds elements to the list.
Also you should not dynamically allocate containers unless you really, really need to (I've never found a need to).
You aren't actually populating the list with any values. I tested the below code and include a commented explanation.
#include <iostream>
#include <list>
using namespace std;
class A {
public:
A();
void callMe();
private:
int x = 0;
};
A::A()
{
cout << "Constructor called" << endl;
x = 20;
}
void A::callMe() {
cout << "Value of x = " << x << endl;
}
int main() {
const int size = 4;
list<A>* arrayOflistOfA = new list<A>[size];
cout << arrayOflistOfA->size() << endl; // As you can see, size is 0 here - you created a list of nulls.
for (int i = 0; i < size; i++)
{
arrayOflistOfA->push_back(A());
}
// The below code demonstrates how to loop through the array once it's populated.
list<A>::iterator it;
for (auto& a : *arrayOflistOfA)
{
a.callMe();
}
return 0;
}
I got the answer to my question. Firstly I tried to run this code on my mac with GNU C++ compiler but when I ran the same code on an iPhone simulator it crashed. So as #PaulMcKenzie mentioned, I was indeed trying to dereference an invalid iterator.

Trying to change c++ code that was started in linux mint to windows with eclipse, getting stack error

I've began making a program in linux with c++ and I'm trying to make it work on windows. It compiles fine, but when run I get this error: "1 [main] Trails of Cold Steel Simulator 8748 cygwin_exception::open_stackdumpfile: Dumping stack trace to Trails of Cold Steel Simulator.exe.stackdump". In the stack trace this exception occurs: "Exception: STATUS_ACCESS_VIOLATION". Here's some code;
#include "Tachi.h"
#include "AutumnLeafCutter.h"
#include <iostream>
#include "Weapon.h"
#include "Armour.h"
#include "Shoes.h"
int main() {
int stats[12] = {15,110,10,4,2,1,2,4,4,3,7,1};
Tachi* Tachi1 = new Tachi(stats, "Tachi");
Tachi1->addEquipment(new PracticeSword());
Tachi1->addEquipment(new LeatherJacket());
Tachi1->addEquipment(new WorkBoots());
Tachi1->addMasterQuartz(new Forcelvl1());
std::string input;
std::cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
while(input != "q") {
std::cout << "Your current stats are:" << std::endl;
std::cout << "\n";
std::cout << "HP EP STR DEF ATS ADF SPD DEX AGL MOV RNG" << std::endl;
for(int i = 0; i < 12; i += 1) {
std::cout << Tachi1->getBaseStats()[i] << " ";
}
std::cout << "\n\n";
std::cout << "Select a Craft by typing its name:" << std::endl;
std::cout << std::endl;
for(int i = 0; i < Tachi1->getCrafts().size(); i++) {
std::cout << Tachi1->getCrafts()[i]->getName() << std::endl;
}
std::cout << std::endl;
getline(std::cin, input);
if(Tachi1->findCraft(input) != NULL) {
Tachi1->useCraft(input);
} else {
std::cout << "You do not have this craft." << std::endl;
}
std::cout << "\n\n\n";
}
}
Im extremely sorry for any formatting, I've never posted here. The error comes from lines 14,15,16 and 18. When I replaced all the "new xxx()" with NULL and comment out the body of the function with them, the program works. It does this for both addEquipment() and addMasterQuartz(). This is the functions;
void Character::addEquipment(Equipment* e) {
equipment.push_back(e);
std::cin.get();
for(int i = 0; i < 12; i++) {
baseStats[i] += equipment[equipment.size()]->getStatsModifier()[i];
}
}
and
void Character::addMasterQuartz(MasterQuartz* mq) {
masterQuartz = mq;
for(int i = 0; i < 12; i++) {
baseStats[i] += masterQuartz->getStatsModifier()[i];
}
}
Im guessing its a problem with the baseStats[i] += xxx stuff as its the only thing that occurs in both, but I have no idea how to fix that. It could also occur when the stuff is made using new xxx().
I can provide whatever else is needed. Thanks!!!!
EDIT:
I kept testing and the problem seems to lie in the creating of the objects. It worked on linux. Here is one of the object codes, they are all similiar and all crash the program;
#include "Armour.h"
Armour::Armour(int* sm, std::string n):Equipment(sm, n) {}
LeatherJacket::LeatherJacket():Armour(stats, armourName) {}
with header file;
#ifndef ARMOUR_H
#define ARMOUR_H
#include "Equipment.h"
class Armour:public Equipment {
public:
Armour(int* sm, std::string n);
};
class LeatherJacket:public Armour {
int stats[12] = {0,0,0,5,0,0,0,0,0,0,0,0};
std::string armourName = "Leather Jacket";
public:
LeatherJacket();
};
#endif
As soon as I remembered I did this I tried compiling (I think) with -std=c++11, it didnt help.
This is your error
baseStats[i] += equipment[equipment.size()]->getStatsModifier()[i];
By definition this is an out of bounds access on your vector, if a vector has a certain size, then the valid indexes are 0 to size - 1, not 0 to size.
It's fairly obvious that you wanted to access the last item in the vector. You can do that like this
baseStats[i] += equipment[equipment.size() - 1]->getStatsModifier()[i];
but even clearer is to use the back method.
baseStats[i] += equipment.back()->getStatsModifier()[i];
Another way would be to use the e variable you've just pushed onto the vector.
baseStats[i] += e->getStatsModifier()[i];
Adding some detail to the problem spotted by Useless, this code is incorrect.
class LeatherJacket : public Armour {
int stats[12] = {0,0,0,5,0,0,0,0,0,0,0,0};
std::string armourName = "Leather Jacket";
public:
LeatherJacket();
};
LeatherJacket::LeatherJacket() : Armour(stats, armourName) {}
The problem is the order in which things happen. First the Armour constructor is called, then the stats and armourName variables are initialised. So the call to the Armour constructor is using uninitiialised variables and will likely crash.
Several solutions possible, the best is probably to use virtual functions.
Making a couple of assumptions about Equipment (which isn't specified the question) it seems you should do something like this.
// header file
class Equipment
{
public:
virtual ~Equipment() {}
virtual std::string getName() const = 0;
virtual const int* getStatsModifier() const = 0;
};
class Armour : public Equipment
{
};
class LeatherJacket : public Armour
{
static const int stats[12];
public:
virtual std::string getName() const { return "Leather Jacket"; }
virtual const int* getStatsModifier() const { return stats; }
};
// source file
const int LeatherJacket::stats[12] = {0,0,0,5,0,0,0,0,0,0,0,0};
This answer adds pure virtual functions to the base class Equipment (which has become an interface), and implements those functions in LeatherJacket. Because the functions are virtual the appropriate function will always be called and there no need to pass the information down to Equipment. Also since it seems to be per-class constant data, stats has been made static const. Until you get to C++17 static const arrays must be defined in a source file, not the header file, as shown above.
Firstly, I'm going to replace the int[12] arrays with a proper type. Partly so the magic number 12 isn't littered all over the code and hard to change later, and partly because it will behave better (ie, not decay to a pointer in some contexts). This needs C++11.
#include <array>
using Stats = std::array<int, 12>;
To me it looks like Armour should have stats and a name, initialized from the arguments passed to its constructor (which you currently ignore).
Like so:
class Armour: public Equipment {
public:
Stats m_stats;
std::string m_name;
Armour(Stats const& s, std::string const &n) : m_stats(s), m_name(n) {}
};
You were already passing those two arguments to the constructor - you just weren't doing anything with them. Now you are.
This means that when we later have leather, scale, chain and plate subclasses, I can have a pointer of type Armour* and not need to worry about which subclass I'm looking at: the stats are available right there in the base class.
I made the members public, which is generally bad style, to save space. It might not matter for your use. I named the members with the m_ prefix so they can't accidentally get confused with similarly-named non-members. It's broadly good style but not essential.
LeatherArmour doesn't need an additional copy per instance, it just needs one of each for the whole class - so they should be const static members.
class LeatherJacket: public Armour {
static const Stats stats {0,0,0,5,0,0,0,0,0,0,0,0};
static const std::string name{"Leather Jacket"};
public:
LeatherJacket() : Armour(stats, name) {}
};
I made the LeatherJacket-specific stat values static const by writing static const in front of them.
The static means that every LeatherJacket has the same base stats, so you don't need a copy per instance, just one copy for the whole class. It's const because the base stats for leather jackets never change over time. You still have the base class member Armour::m_stats which can change as your individual leather jacket gets damaged, repaired, buffed or whatever.
Again, the LeatherJacket constructor was already passing (the equivalent of) these members to the base class constructor, but now they already exist (see the link above about static storage duration). The original instance variables didn't exist when you used them, because the derived (LeatherJacket) object and its data members aren't really constructed until after the base class subobject.

Is it possible to avoid managing memory manually in this situation in c++?

I have a Storage class that keeps a list of Things:
#include <iostream>
#include <list>
#include <functional>
class Thing {
private:
int id;
int value = 0;
static int nextId;
public:
Thing() { this->id = Thing::nextId++; };
int getId() const { return this->id; };
int getValue() const { return this->value; };
void add(int n) { this->value += n; };
};
int Thing::nextId = 1;
class Storage {
private:
std::list<std::reference_wrapper<Thing>> list;
public:
void add(Thing& thing) {
this->list.push_back(thing);
}
Thing& findById(int id) const {
for (std::list<std::reference_wrapper<Thing>>::const_iterator it = this->list.begin(); it != this->list.end(); ++it) {
if (it->get().getId() == id) return *it;
}
std::cout << "Not found!!\n";
exit(1);
}
};
I started with a simple std::list<Thing>, but then everything is copied around on insertion and retrieval, and I didn't want this because if I get a copy, altering it does not reflect on the original objects anymore. When looking for a solution to that, I found about std::reference_wrapper on this SO question, but now I have another problem.
Now to the code that uses them:
void temp(Storage& storage) {
storage.findById(2).add(1);
Thing t4; t4.add(50);
storage.add(t4);
std::cout << storage.findById(4).getValue() << "\n";
}
void run() {
Thing t1; t1.add(10);
Thing t2; t2.add(100);
Thing t3; t3.add(1000);
Storage storage;
storage.add(t3);
storage.add(t1);
storage.add(t2);
temp(storage);
t2.add(10000);
std::cout << storage.findById(2).getValue() << "\n";
std::cout << storage.findById(4).getValue() << "\n";
}
My main() simply calls run(). The output I get is:
50
10101
Not found!!
Although I was looking for:
50
10101
50
Question
Looks like the locally declared object t4 ceases to exist when the function returns, which makes sense. I could prevent this by dynamically allocating it, using new, but then I didn't want to manage memory manually...
How can I fix the code without removing the temp() function and without having to manage memory manually?
If I just use a std::list<Thing> as some suggested, surely the problem with t4 and temp will cease to exist, but another problem will arise: the code won't print 10101 anymore, for example. If I keep copying stuff around, I won't be able to alter the state of a stored object.
Who is the owner of the Thing in the Storage?
Your actual problem is ownership. Currently, your Storage does not really contain the Things but instead it is left to the user of the Storage to manage the lifetime of the objects you put inside it. This is very much against the philosophy of std containers. All standard C++ containers own the objects you put in them and the container manages their lifetime (eg you simply call v.resize(v.size()-2) on a vector and the last two elements get destroyed).
Why references?
You already found a way to make the container not own the actual objects (by using a reference_wrapper), but there is no reason to do so. Of a class called Storage I would expect it to hold objects not just references. Moreover, this opens the door to lots of nasty problems, including undefined behaviour. For example here:
void temp(Storage& storage) {
storage.findById(2).add(1);
Thing t4; t4.add(50);
storage.add(t4);
std::cout << storage.findById(4).getValue() << "\n";
}
you store a reference to t4 in the storage. The thing is: t4s lifetime is only till the end of that function and you end up with a dangling reference. You can store such a reference, but it isnt that usefull because you are basically not allowed to do anything with it.
Aren't references a cool thing?
Currently you can push t1, modify it, and then observe that changes on the thingy in Storage, this might be fine if you want to mimic Java, but in c++ we are used to containers making a copy when you push something (there are also methods to create the elements in place, in case you worry about some useless temporaries). And yes, of course, if you really want you can make a standard container also hold references, but lets make a small detour...
Who collects all that garbage?
Maybe it helps to consider that Java is garbage-collected while C++ has destructors. In Java you are used to references floating around till the garbage collector kicks in. In C++ you have to be super aware of the lifetime of your objects. This may sound bad, but acutally it turns out to be extremely usefull to have full control over the lifetime of objects.
Garbage? What garbage?
In modern C++ you shouldnt worry to forget a delete, but rather appreciate the advantages of having RAII. Acquiring resources on initialzation and knowing when a destructor gets called allows to get automatic resource management for basically any kind of resource, something a garbage collector can only dream of (think of files, database connections, etc.).
"How can I fix the code without removing the temp() function and without having to manage memory manually?"
A trick that helped me a lot is this: Whenever I find myself thinking I need to manage a resource manually I stop and ask "Can't someone else do the dirty stuff?". It is really extremely rare that I cannot find a standard container that does exactly what I need out of the box. In your case, just let the std::list do the "dirty" work.
Can't be C++ if there is no template, right?
I would actually suggest you to make Storage a template, along the line of:
template <typename T>
class Storage {
private:
std::list<T> list;
//....
Then
Storage<Thing> thing_storage;
Storage<int> int_storage;
are Storages containing Things and ints, respectively. In that way, if you ever feel like exprimenting with references or pointers you could still instantiate a Storage<reference_wrapper<int>>.
Did I miss something?...maybe references?
I won't be able to alter the state of a stored object
Given that the container owns the object you would rather let the user take a reference to the object in the container. For example with a vector that would be
auto t = std::vector<int>(10,0); // 10 element initialized to 0
auto& first_element = t[0]; // reference to first element
first_element = 5; // first_element is an alias for t[0]
std::cout << t[0]; // i dont want to spoil the fun part
To make this work with your Storage you just have to make findById return a reference. As a demo:
struct foo {
private:
int data;
public:
int& get_ref() { return data;}
const int& get_ref() const { return data;}
};
auto x = foo();
x.get_ref = 12;
TL;DR
How to avoid manual resource managment? Let someone else do it for you and call it automatic resource management :P
t4 is a temporary object that is destroyed at exit from temp() and what you store in storage becomes a dangling reference, causing UB.
It is not quite clear what you're trying to achieve, but if you want to keep the Storage class the same as it is, you should make sure that all the references stored into it are at least as long-lived as the storage itself. This you have discovered is one of the reasons STL containers keep their private copies of elements (others, probably less important, being—elimination of an extra indirection and a much better locality in some cases).
P.S. And please, can you stop writing those this-> and learn about initialization lists in constructors? >_<
In terms of what your code actually appears to be doing, you've definitely overcomplicated your code, by my estimation. Consider this code, which does all the same things your code does, but with far less boilerplate code and in a way that's far more safe for your uses:
#include<map>
#include<iostream>
int main() {
std::map<int, int> things;
int & t1 = things[1];
int & t2 = things[2];
int & t3 = things[3];
t1 = 10;
t2 = 100;
t3 = 1000;
t2++;
things[4] = 50;
std::cout << things.at(4) << std::endl;
t2 += 10000;
std::cout << things.at(2) << std::endl;
std::cout << things.at(4) << std::endl;
things.at(2) -= 75;
std::cout << things.at(2) << std::endl;
std::cout << t2 << std::endl;
}
//Output:
50
10101
50
10026
10026
Note that a few interesting things are happening here:
Because t2 is a reference, and insertion into the map doesn't invalidate references, t2 can be modified, and those modifications will be reflected in the map itself, and vise-versa.
things owns all the values that were inserted into it, and it will be cleaned up due to RAII, and the built-in behavior of std::map, and the broader C++ design principles it is obeying. There's no worry about objects not being cleaned up.
If you need to preserve the behavior where the id incrementing is handled automatically, independently from the end-programmer, we could consider this code instead:
#include<map>
#include<iostream>
int & insert(std::map<int, int> & things, int value) {
static int id = 1;
int & ret = things[id++] = value;
return ret;
}
int main() {
std::map<int, int> things;
int & t1 = insert(things, 10);
int & t2 = insert(things, 100);
int & t3 = insert(things, 1000);
t2++;
insert(things, 50);
std::cout << things.at(4) << std::endl;
t2 += 10000;
std::cout << things.at(2) << std::endl;
std::cout << things.at(4) << std::endl;
things.at(2) -= 75;
std::cout << things.at(2) << std::endl;
std::cout << t2 << std::endl;
}
//Output:
50
10101
50
10026
10026
These code snippets should give you a decent sense of how the language works, and what principles, possibly unfamiliar in the code I've written, that you need to learn about. My general recommendation is to find a good C++ resource for learning the basics of the language, and learn from that. Some good resources can be found here.
One last thing: if the use of Thing is critical to your code, because you need more data saved in the map, consider this instead:
#include<map>
#include<iostream>
#include<string>
//Only difference between struct and class is struct sets everything public by default
struct Thing {
int value;
double rate;
std::string name;
Thing() : Thing(0,0,"") {}
Thing(int value, double rate, std::string name) : value(value), rate(rate), name(std::move(name)) {}
};
int main() {
std::map<int, Thing> things;
Thing & t1 = things[1];
t1.value = 10;
t1.rate = 5.7;
t1.name = "First Object";
Thing & t2 = things[2];
t2.value = 15;
t2.rate = 17.99999;
t2.name = "Second Object";
t2.value++;
std::cout << things.at(2).value << std::endl;
t1.rate *= things.at(2).rate;
std::cout << things.at(1).rate << std::endl;
std::cout << t1.name << "," << things.at(2).name << std::endl;
things.at(1).rate -= 17;
std::cout << t1.rate << std::endl;
}
Based on what François Andrieux and Eljay have said (and what I would have said, had I got there first), here is the way I would do it, if you want to mutate objects you have already added to a list. All that reference_wrapper stuff is just a fancy way of passing pointers around. It will end in tears.
OK. here's the code (now edited as per OP's request):
#include <iostream>
#include <list>
#include <memory>
class Thing {
private:
int id;
int value = 0;
static int nextId;
public:
Thing() { this->id = Thing::nextId++; };
int getId() const { return this->id; };
int getValue() const { return this->value; };
void add(int n) { this->value += n; };
};
int Thing::nextId = 1;
class Storage {
private:
std::list<std::shared_ptr<Thing>> list;
public:
void add(const std::shared_ptr<Thing>& thing) {
this->list.push_back(thing);
}
std::shared_ptr<Thing> findById(int id) const {
for (std::list<std::shared_ptr<Thing>>::const_iterator it = this->list.begin(); it != this->list.end(); ++it) {
if (it->get()->getId() == id) return *it;
}
std::cout << "Not found!!\n";
exit(1);
}
};
void add_another(Storage& storage) {
storage.findById(2)->add(1);
std::shared_ptr<Thing> t4 = std::make_shared<Thing> (); t4->add(50);
storage.add(t4);
std::cout << storage.findById(4)->getValue() << "\n";
}
int main() {
std::shared_ptr<Thing> t1 = std::make_shared<Thing> (); t1->add(10);
std::shared_ptr<Thing> t2 = std::make_shared<Thing> (); t2->add(100);
std::shared_ptr<Thing> t3 = std::make_shared<Thing> (); t3->add(1000);
Storage storage;
storage.add(t3);
storage.add(t1);
storage.add(t2);
add_another(storage);
t2->add(10000);
std::cout << storage.findById(2)->getValue() << "\n";
std::cout << storage.findById(4)->getValue() << "\n";
return 0;
}
Output is now:
50
10101
50
as desired. Run it on Wandbox.
Note that what you are doing here, in effect, is reference counting your Things. The Things themselves are never copied and will go away when the last shared_ptr goes out of scope. Only the shared_ptrs are copied, and they are designed to be copied because that's their job. Doing things this way is almost as efficient as passing references (or wrapped references) around and far safer. When starting out, it's easy to forget that a reference is just a pointer in disguise.
Given that your Storage class does not own the Thing objects, and every Thing object is uniquely counted, why not just store Thing* in the list?
class Storage {
private:
std::list<Thing*> list;
public:
void add(Thing& thing) {
this->list.push_back(&thing);
}
Thing* findById(int id) const {
for (auto thing : this->list) {
if (thing->getId() == id) return thing;
}
std::cout << "Not found!!\n";
return nullptr;
}
};
EDIT: Note that Storage::findById now returns Thing* which allows it to fail gracefully by returning nullptr (rather than exit(1)).

Creating a class member that is automatically calculated from other class members?

I'm an absolute newbee when it comes to programming and I'm trying to teach myself the basics by just solving some easy "problems" in C++.
I have searched the web for an exact answer to my question before posting it here and haven't found one so far, however that may be because of (1).
So, what I'm looking for is a way to declare a class member that gets automatically calculated from other members of the same class, so that the calculated class member can be used just like an explicitly defined class member would. For example imagine a struct called creature that has the properties/members creature.numberofhands, creature.fingersperhand and finally the property creature.totalfingers that automatically gets calculated from the above members.
Heres an example of the closest I got to what I wanted to achieve:
#include <iostream>
typedef struct creature {
int numberofhands;
int fingersperhand;
int totalfingers();
} creature;
int creature::totalfingers()
{
return numberofhands * fingersperhand;
};
int main()
{
creature human;
human.numberofhands = 2;
human.fingersperhand = 5;
printf("%d",human.totalfingers());
return(0);
}
What's really annoying me about this, is that I have to treat the calculated one DIFFERENTLY from the explicitly defined ones, i.e. I have to put "()" after it.
How can I change the code, so I can use: human.totalfingers without ever explicitly defining it?
The simplest option would be to use public member functions and make the actual properties hidden.
Something like this:
class Creature {
public:
Creature(int numhands, int fingersperhand) // constructor
: m_numhands{numhands}, m_fingersperhand{fingersperhand}
{ }
int fingersPerHand() const { return m_fingersperhand; }
int numberOfHands() const { return m_numhands; }
int totalFingers() const { return numberOfHands() * fingersPerHand(); }
private:
const int m_numhands;
const int m_fingersperhand;
};
The private member variables are an implementation detail. Users of the class just use the three public member functions to get the different number of fingers after construction and don't need to care that two of them are returning constant stored numbers and the third returns a calculated value - that's irrelevant to users.
An example of use:
#include <iostream>
int main()
{
Creature human{2, 5};
std::cout << "A human has "
<< human.totalFingers() << " fingers. "
<< human.fingersPerHand() << " on each of their "
<< human.numberOfHands() << " hands.\n";
return 0;
}
If - as per your comment - you don't want to use a constructor (although that's the safest way to ensure you don't forget to initialize a member), you can modify the class like this:
class CreatureV2 {
public:
int fingersPerHand() const { return m_fingersperhand; }
int numberOfHands() const { return m_numhands; }
int totalFingers() const { return numberOfHands() * fingersPerHand(); }
void setFingersPerHand(int num) { m_fingersperhand = num; }
void setNumberOfHands(int num) { m_numhands = num; }
private:
// Note: these are no longer `const` and I've given them default
// values matching a human, so if you do nothing you'll get
// human hands.
int m_numhands = 2;
int m_fingersperhand = 5;
};
Example of use of the modified class:
#include <iostream>
int main()
{
CreatureV2 human;
std::cout << "A human has "
<< human.totalFingers() << " fingers. "
<< human.fingersPerHand() << " on each of their "
<< human.numberOfHands() << " hands.\n";
CreatureV2 monster;
monster.setFingersPerHand(7);
monster.setNumberOfHands(5);
std::cout << "A monster has "
<< monster.totalFingers() << " fingers. "
<< monster.fingersPerHand() << " on each of their "
<< monster.numberOfHands() << " hands.\n";
CreatureV2 freak;
freak.setFingersPerHand(9);
// Note: I forgot to specify the number of hands, so a freak get
// the default 2.
std::cout << "A freak has "
<< freak.totalFingers() << " fingers. "
<< freak.fingersPerHand() << " on each of their "
<< freak.numberOfHands() << " hands.\n";
return 0;
}
Note: all of the above assumes you are using a modern C++14 compiler.
What you have described is one of the reasons why encapsulation and "member variables should be private" is the recommended way of doing things in C++.
If every variable is accessed through a function, then everything is consistent, and refactoring from a member variable to a computation is possible.
Some languages, like C# or D, have the concept of "properties", which provide a way around the issue, but C++ does not have such a construct.
For fun, the proxy way to avoid extra parenthesis, (but with some extra costs):
class RefMul
{
public:
RefMul(int& a, int& b) : a(a), b(b) {}
operator int() const { return a * b; }
private:
int& a;
int& b;
};
struct creature {
int numberofhands;
int fingersperhand;
RefMul totalfingers{numberofhands, fingersperhand};
};
Demo
Note: to use RefMul with printf, you have to cast to int:
printf("%d", int(human.totalfingers));
That cast would not be required if you use c++ way to print:
std::cout << human.totalfingers;
If you're after consistency, you can make your changes the other way around. Replace the two member variables with constant methods which simply return copies of the member variables. That way, the way you access data is consistent and you don't have to worry about some code changing the values of the member variables when it shouldn't.
Others have provided very good answers. If you are looking for consistency, probably the easiest way is to make use of member functions (as #Jesper Juhl has answered).
On the other hand, if you strictly want to use class members that are calculated automatically from other members, you can use properties. Properties (as are defined in C# and Groovy) are not a standard feature of C++ but there are ways to implement them in C++. This SO question has a very good overview of the ways that properties can be defined and used in C++. My favorite way of defining properties is taking advantage of Microsoft-specific extension for properties in Visual C++ (obviously, this approach is specific to Microsoft Visual C++). A documentation of properties in Visual C++ can be found in MSDN. Using properties in Visual C++, your code can be modified to:
struct creature {
int numberofhands; // use of public member variables are generally discouraged
int fingersperhand;
__declspec(property(get = get_totalfingers)) // Microsoft-specific
int totalfingers;
private:
int fingers;
int get_totalfingers()
{
return numberofhands * fingersperhand; // This is where the automatic calculation takes place.
}
};
This class can be used like this:
#include <iostream>
int main()
{
creature martian;
martian.numberofhands = 2;
martian.fingersperhand = 4; // Marvin the Martian had 4!
// This line will print 8
std::cout << "Total fingers: " << martian.totalfingers << std::endl;
return 0;
}
As I said earlier, properties are not a standard feature of C++ but there are ways to get them in C++ which either rely on smart tricks or using compiler-specific features. IMHO, using simple functions (as #Jesper Juhl described) is a better alternative.