Question in short:
class B has a ptr to class C, which has a class D having a ptr to class B
assign class B to an array in class A by copying, expecting to see to ptr points to new instance in the array not original instance, but failed.
I am already able to do some workaround, but I want to know why my original approach fails.
More detailed explainations are as follows, and the code to reproduce the problem is posted as well
Anyone who is able to explain what is going on is appreciated.
There are 6 classes:
class CastInfo //contains a Character*
class Skill //abstract class, contains CastInfo
class Movvement : public Skill
class Move1 : public Movement
class Character //contains a Movement*, which will be Move1* in practice
class Squad //contains an array of Character
with the following relationships:
Character* in CastInfo should point to the Character who owns the Skill which
is the owner of CastInfo
when assigning the Skill to Character, the Character* in CastInfo points to that Character
the Character in Squad's array should be copied, so there will be 2 instances and the Character* in CastInfo should also point to Character in Squad's array not original instance
The expecting result is:
move1 != ch1.move1 != squad.ch[0].move1 (this is already satisfied)
ch1.move1->cast_info.caster == &ch1 != squad.ch[0].move1->caster_info.caster (this is the problem)
There are 2 cases (tried) of the output:
In the Squad's constructor,:
if using
characters_[i] = characters[i];
the character is correctly copied, but the skill is at same address
move1: 00000270E6093500
ch1: 000000BC6DCFF378
ch1.move1: 00000270E6093E60
ch1.move1->cast_info.caster: 000000BC6DCFF378
squad.ch[0]: 000000BC6DCFF3E0
squad.ch[0].move1: 00000270E6093E60
squad.ch[0].move1->cast_info.caster: 000000BC6DCFF378
if using
characters_[i] = Character(characters[i]);
the character is correctly copied, but the skill is missing (pointing to some weird location)
move1: 00000230FDCEF080
ch1: 00000058A11DF548
ch1.move1: 00000230FDCEF260
ch1.move1->cast_info.caster: 00000058A11DF548
squad.ch[0]: 00000058A11DF5B0
squad.ch[0].move1: 00000230FDCEF0E0
squad.ch[0].move1->cast_info.caster: 00000058A11DF378
In the first case, I guess it is probably because I did not overload operator=, so only address is copied. I tried to overload it but it caused more problem. (Such as when using Builder.Build() )
In the second case, I expect it first call copy constructor, which triggers SetMove1(), which calls SetCaster(). move1 is cloned as shown, but I cannot understand why caster is not updated correctly. (Though is calls operator= after construnction, the address should remain the same.)
The following code should reproduce the problem:
motion.h
#pragma once
class Character;
struct CastInfo
{
Character* caster;
int coeff;
};
class Skill
{
public:
CastInfo cast_info;
Skill() {};
~Skill() {};
virtual void DoSomething() = 0;
};
class Movement : public Skill
{
public:
Movement();
~Movement();
virtual void DoSomething() { ; }
virtual Movement* Clone() const { return new Movement(*this); }
};
class Move1 : public Movement
{
public:
Move1() { cast_info.coeff = 123; }
void DoSomething() { ; }
virtual Move1* Clone() const { return new Move1(*this); }
};
class Move2 : public Movement
{
public:
void DoSomething() { ; }
};
motion.cpp:
#include "motion.h"
Movement::Movement() { }
Movement::~Movement() { }
test.h:
#pragma once
#include <string>
#include <vector>
#include "motion.h"
#define SQUAD_SIZE 6
extern Movement* null_movement;
class Character
{
public:
class Builder;
Character();
~Character();
Character(const Character& character);
Character& SetMove1(Movement* skill);
public:
int id_;
Movement* move1_ = null_movement;
Movement* move2_ = null_movement;
Character(int id) : id_(id) { ; }
void SetCaster();
};
class Character::Builder : public Character
{
public:
Builder& SetId(int i) { id_ = i; return *this; }
Character Build() { return Character(id_); }
};
class Squad
{
public:
class Builder;
Squad() { }
Squad(const Squad& squad);
~Squad() { }
public:
Character characters_[SQUAD_SIZE];
Squad(Character* characters);
};
class Squad::Builder :public Squad
{
public:
Builder& SetCharacter(const Character& character, const int position) { characters_[position] = character; return *this; }
Squad Build() { return Squad(characters_); }
};
test.cpp
#include <iostream>
#include "test.h"
Movement* null_movement = new Move2();
Character::Character() : id_(0) { }
Character::~Character() {}
Character::Character(const Character& character) {
id_ = character.id_;
SetMove1(character.move1_);
}
Character& Character::SetMove1(Movement* move1) {
if (!move1) return *this;
move1_ = move1->Clone();
SetCaster();
return *this;
}
void Character::SetCaster() {
if (move1_ != NULL) move1_->cast_info.caster = this;
}
Squad::Squad(const Squad& squad) {
*this = squad;
}
Squad::Squad(Character* characters) {
for (int i = 0; i < SQUAD_SIZE; i++) {
//characters_[i] = characters[i]; //character copied, skill same address
characters_[i] = Character(characters[i]); //character copied, skill missing
}
}
main.cpp
#include <iostream>
#include "test.h"
#include "motion.h"
int main() {
Move1* move1 = new Move1();
std::cout << "move1: " << move1 << std::endl;
Character ch1 = Character::Builder().SetId(1).Build();
Character ch2 = Character::Builder().SetId(2).Build();
ch1.SetMove1(move1);
std::cout << "ch1: " << &ch1 << std::endl;
std::cout << "ch1.move1: " << (ch1.move1_) << std::endl;
std::cout << "ch1.move1->cast_info.caster: " << (ch1.move1_->cast_info.caster) << std::endl;
Squad squad = Squad::Builder().SetCharacter(ch1, 0).SetCharacter(ch2, 1).Build();
std::cout << "squad.ch[0]: " << &(squad.characters_[0]) << std::endl;
std::cout << "squad.ch[0].move1: " << (squad.characters_[0].move1_) << std::endl;
std::cout << "squad.ch[0].move1->cast_info.caster: " << (squad.characters_[0].move1_->cast_info.caster) << std::endl;
system("PAUSE");
return 0;
}
As previously mentioned, I have a workaround to reach my goal:
By creating another method, which iterates through the array in Squad, and call each Character's SetCaster() method.
void Squad::SetCaster() {
for (int i = 0; i < SQUAD_SIZE; i++) {
characters_[i].SetCaster();
}
}
But I think this is dirty because every time after Builder::Builder(), SetCaster() must be called, which is unintuitive and error-prone.
I think I found the problem, as illustrated below:
The problem is in
Squad::Squad(Character* characters) {
for (int i = 0; i < SQUAD_SIZE; i++) {
//characters_[i] = characters[i]; //character copied, skill same address
characters_[i] = Character(characters[i]); //character copied, skill missing
}
}
As mentioned in question, using the commented line is just copying the values, which is incorrect.
What
characters_[i] = Character(characters[i]); //character copied, skill missing
does is as follows:
create a Character, by calling Character's constructer, this object is at address A. SetMove1() is called, SetCaster() is called. The pointer in cast_info is pointing at A correctly.
assign the object to characters_[i], whose address is at address B because the address of characters_ is assigned when Squad is created. As I did not overload Character::operator=, the pointer is still pointing to address A
Constructor done, Squad returned.
This is the reason
std::cout << "squad.ch[0].move1->cast_info.caster: " << (squad.characters_[0].move1_->cast_info.caster) << std::endl;
shows a third address (address A) which is neither &(character[0]) (address B) nor &ch1 (original character's address)
The solution is either to overload operator= or put my "workaround" (Squad::SetCaster()) in constructor right after the for loop.
Please correct me if there is anything wrong, or if there is any better solution.
Related
I am currently working on a chess engine in C++, and in the engine, I'm trying to modify a string variable "piece" inside of a class "ChessTile" within another class called "ChessBoard".
Anyways when I use a function to return a class, then modify said class, it doesn't change the source variable, and I was wondering how you do that.
Here is a simple script I wrote to demonstrate:
#include <iostream>
#include <string>
class child {
private:
int myVar;
public:
child(int v) {
myVar = v;
}
int getVar() {
return myVar;
}
int setVar(int Svar) {
this->myVar = Svar;
return 0;
}
};
class parent {
public:
child baby = child(0);
child findMyChild(int var) {
if (var == 1) {
return baby;
}
}
};
parent DAD;
int main() {
std::cout << DAD.findMyChild(1).getVar() << std::endl;
DAD.findMyChild(1).setVar(50);
std::cout << DAD.findMyChild(1).getVar() << std::endl;
}
The output for this is:
0
0
But I'm wanting it to be:
0
50
If necessary, I can also post my chess engine. Thank you!
In your code, findMyChild() is returning a copy of the baby ( function returning by value), use return by reference instead like so.
child& parent::findMyChild(int var) {
if (var == 1)
{
return baby;
}
/* other codes */
return baby;
}
You are returning a copy of child in findMyChild. Therefore, you modify only that copy, not the member itself.
You should return a pointer to the member
child* findMyChild(int var) {
return var == 1
? &baby
: nullptr;
}
then dereference it to get/set its value. For example:
DAD.findMyChild(1)->setVar(50);
Since findMyChild can return null pointer in my code you should check its existence before accessing
child* c = DAD.findMyChild(1);
if (c) c->setVar(50);
You can do it via returning pointer/reference of child as stated by another comment or you can do it via an interface in parent class.
#include <iostream>
#include <string>
#define FIRST_CHILD 1
#define CANNOT_FIND_CHILD -1
class child {
private:
int myVar;
public:
child(int v) {
myVar = v;
}
int childGetVar() {
return myVar;
}
int childSetVar(int Svar) {
this->myVar = Svar;
return 0;
}
};
class parent {
public:
child baby = child(0);
int getVar(int var) {
if (var == FIRST_CHILD)
return baby.childGetVar();
return CANNOT_FIND_CHILD;
}
int setVar(int var, int Svar) {
if (var == FIRST_CHILD)
baby.childSetVar(Svar);
return CANNOT_FIND_CHILD;
}
};
parent DAD;
int main() {
std::cout << DAD.getVar(FIRST_CHILD) << std::endl;
DAD.setVar(FIRST_CHILD, 50);
std::cout << DAD.getVar(FIRST_CHILD) << std::endl;
}
I want to use the derived class B::display() and C::display(), but it uses A::display(). How do I change the code so that I can call the derived class' display() to display the id together with name?
Thanks in advance :)
#include <iostream>
#include <vector>
using namespace std;
class A
{
protected :
int id;
public:
A ( int id = 0 ) : id(id) {}
virtual void display() { cout << id << endl; }
};
class B : public A
{
string name;
public:
B ( int id = 0, string name = "-" ) : A(id), name(name) {}
void display() { cout << id << " " << name << endl; }
};
class C : public A
{
string name;
public:
C ( int id = 0, string name = "-" ) : A(id), name(name) {}
void display() { cout << id << " " << name << endl; }
};
int main()
{
vector< vector <A> > aa;
vector<A> bb ;
vector<A> cc ;
A *yy = new B(111, "Patrick");
A *zz = new C(222, "Peter");
bb.push_back(*yy);
cc.push_back(*zz);
aa.push_back(bb);
aa.push_back(cc);
for ( int i = 0; i < aa[0].size(); i++)
{
aa[0][i].display();
aa[1][i].display();
}
}
your problem his that you are declartion of the vector is of non pointer type , and on runtime you are losing the "point" to the subclass and you just stay with the super class.
all you have to do is change all of your vectors to pointer type , like that:
vector<A*> bb;
The issue here is in order for inheritance to work you need to use pointers. your vector is a vector<A> and not a vector<A*> so when you push-back the dereferences version of yy and zz you are pushing back the copy of their A data members not a copy of the B and C data members. The size of B and C is different then A so it will only do a copy of data members that will fit in the place of A object.
http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/
You can't expect polymorphism to work without pointers.
Change your main part to
vector< vector <A*> > aa;
vector<A*> bb;
vector<A*> cc;
A* yy = new B(111, "Patrick");
A* zz = new C(222, "Peter");
bb.push_back(yy);
cc.push_back(zz);
aa.push_back(bb);
aa.push_back(cc);
for (int i = 0; i < aa[0].size(); i++)
{
aa[0][i]->display();
aa[1][i]->display();
}
so basically I have some c++ code in VS2013 that looks like this
#include "stdafx.h"
#include <malloc.h>
#include <stdio.h>
class Test_Class {
public:
Test_Class() {
printf("In Test_Class()\n");
allocated_array = (int*)malloc(sizeof(int) * 64);
printf("Allocated %p\n", allocated_array);
}
~Test_Class() {
printf("In ~Test_Class()\n");
printf("Freeing %p\n", allocated_array);
free(allocated_array);
printf("Freed %p\n", allocated_array);
}
private:
int* allocated_array;
};
class Holder {
public:
Holder() {
printf("In Holder()\n");
m_test_class = Test_Class();
}
~Holder() {
printf("In ~Holder()\n");
}
private:
Test_Class m_test_class;
};
class Game {
public:
Game() {
printf("In Game()\n");
m_holder = Holder();
}
~Game() {
printf("In ~Game()");
}
private:
Holder m_holder;
};
int main()
{
printf("In main()\n");
Game game = Game();
return 0;
}
That when ran, gives me this output:
What I'm wondering is, why is the destructor of the same Test_Class object getting called twice before it crashes (due to trying to free the same pointer twice). I went through with the debugger, to make sure it wasn't just a new instance of the class that had been given the same pointer as the other object, and sure enough it was the exact same object.
I understand that since the Test_Class object is a member of Holder, that it would create a Test_Class object, then create another one and destroy the old one (which it seems to do), but this weird behaviour of calling the destructor on the same seems to occur when I make a member of type Holder in the Game class. Obviously there's something I'm missing.
The reason is, that your compiler is not able to eliminate the copy assignment Game game = Game();.
The correct code would be Game game;.
What your code does is to construct an object as rvalue, assign it to a new object game that is a lvalue. So in this line Game game = Game(); two objects are constructed and one of them is immediately destructed after assignment.
Edit:
The same holds for m_Holder and so on - of course.
You might benefit from instrumenting your class to see what's happening. A technique I often use is to create a specific instrumentation class with static counters for each significant event. Here's an example that is little more than a wrapper around a numeric type (specifically double in this case), but it illustrates the idea:
class Goofy
{
private:
double num;
public:
Goofy(double n = 0) : num(n) { ++constructions; }
Goofy(const Goofy &g2) : num(g2.num) { ++copyconstructions; }
Goofy(const Goofy &&g2) : num(g2.num) { ++moves; }
~Goofy() { ++destructions; }
Goofy &operator=(const Goofy &g2) { num = g2.num; return *this; }
Goofy &operator-=(const Goofy &g2) { num -= g2.num; return *this; }
Goofy &operator+=(const Goofy &g2) { num += g2.num; return *this; }
// none of the code below is needed by the new version of the function
Goofy &operator*=(const Goofy &g2) { num *= g2.num; return *this; }
friend std::ostream &operator<<(std::ostream &out, const Goofy &g2) {
return out << g2.num;
}
static void report(int line) {
std::cout << "At line " << line
<< "\nconstructions = " << Goofy::constructions
<< "\n copies = " << Goofy::copyconstructions
<< "\n moves = " << Goofy::moves
<< "\n destructions = " << Goofy::destructions
<< "\n existing = " << Goofy::constructions +
Goofy::copyconstructions + Goofy::moves -
Goofy::destructions
<< '\n';
}
static long constructions;
static long copyconstructions;
static long moves;
static long destructions;
};
long Goofy::constructions = 0;
long Goofy::copyconstructions = 0;
long Goofy::moves = 0;
long Goofy::destructions = 0;
Here's an example of how it was used: https://codereview.stackexchange.com/questions/56532/kahan-summation/56592#56592
There's a lot wrong with your code, but I'm going to go with it anyways. You need to (at a minimum) implement the copy constructor and copy assignment operator. I would use new, delete and swap since this is C++ and not C. Something like this:
Test_Class() {
allocated_array = new int[64];
}
~Test_Class() {
delete[] allocated_array;
}
Test_Class(const Test_Class& rhs)
{
allocated_array = new int[64];
std::copy(&rhs.allocated_array[0], &rhs.allocated_array[0] + 64, &allocated_array[0]);
}
Test_Class& operator=(const Test_Class rhs)
{
if (this != &rhs)
{
Test_Class(rhs).swap(*this);
}
return *this;
}
void swap(Test_Class & s) throw()
{
std::swap(this->allocated_array, s.allocated_array);
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
My first question is: I am having a lot of trouble figuring out why the Example class is being constructed greater than the others. Below is a short app using a Template counter to track how many times the constructor/destructor/copy constructor is called for each class. There are a total of three classes: Example, Deep, Child. Each has a copy constructor... ugh.
Also, my second question, is what would be the correct way to define the copy constructor for the Child class?
In the printStatus(), it displays:
COUNTERS::NEW_COUNTER = 60
COUNTERS::DELETE_COUNTER = 50
COUNTERS::CONSTRUCTOR_COUNTER = 90
COUNTERS::DESTRUCTOR_COUNTER = 80
Example count = 10
Deep count = 0
Child count = 0
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class COUNTERS
{
public:
static int NEW_COUNTER;
static int DELETE_COUNTER;
static int CONSTRUCTOR_COUNTER;
static int DESTRUCTOR_COUNTER;
};
int COUNTERS::NEW_COUNTER = 0;
int COUNTERS::DELETE_COUNTER = 0;
int COUNTERS::CONSTRUCTOR_COUNTER = 0;
int COUNTERS::DESTRUCTOR_COUNTER = 0;
/* template used for counting constructors/destructors to debug memory leaks */
template <typename T>
class Countable
{
static unsigned cs_count_;
public:
Countable() { ++cs_count_; }
Countable( Countable const& ) { ++cs_count_; }
virtual ~Countable() { --cs_count_;}
static unsigned count() { return cs_count_; }
};
template <typename T>
unsigned Countable<T>::cs_count_ = 0;
class Example : public Countable<Example>
{
public:
string a;
int b;
Example() {
COUNTERS::CONSTRUCTOR_COUNTER++;
a = "exampleString";
b = 5;
}
virtual ~Example() {
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Example(const Example& e) {
COUNTERS::CONSTRUCTOR_COUNTER++;
this->a = e.a;
this->b = e.b;
}
};
class Deep : public Countable<Deep>
{
public:
int a;
string b;
Example* e;
Deep()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
a = 3;
b = "deepString";
e = new Example();
COUNTERS::NEW_COUNTER++;
}
virtual ~Deep() {
if(e != NULL) {
delete e;
COUNTERS::DELETE_COUNTER++;
}
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Deep(const Deep& x)
{
COUNTERS::CONSTRUCTOR_COUNTER++;
this->a = x.a;
this->b = x.b;
this->e = new Example();
COUNTERS::NEW_COUNTER++;
this->e->a = x.e->a;
this->e->b = x.e->b;
};
};
class Child : public Countable<Child>
{
public:
Deep d;
string name;
int age;
Example* e;
vector<Example> list;
vector<Deep> deep_list;
void init()
{
Deep* var = new Deep(); COUNTERS::NEW_COUNTER++;
deep_list.push_back(*var);
delete var; COUNTERS::DELETE_COUNTER++;
}
Child() {
COUNTERS::CONSTRUCTOR_COUNTER++;
name = "a";
age = 10;
d.a = 1;
d.b = "deep";
d.e = NULL;
e = new Example();
COUNTERS::NEW_COUNTER++;
list.push_back(*e);
init();
}
virtual ~Child() {
COUNTERS::DESTRUCTOR_COUNTER++;
if(e != NULL) {
delete e;
COUNTERS::DELETE_COUNTER++;
}
}
// copy constructor
Child(const Child& c)
{
}
};
void myChildFunction(){
Child* c = new Child();
COUNTERS::NEW_COUNTER++;
delete c;
COUNTERS::DELETE_COUNTER++;
}
void printStatus(){
cout << "COUNTERS::NEW_COUNTER = " << COUNTERS::NEW_COUNTER << endl;
cout << "COUNTERS::DELETE_COUNTER = " << COUNTERS::DELETE_COUNTER << endl;
cout << "COUNTERS::CONSTRUCTOR_COUNTER = " << COUNTERS::CONSTRUCTOR_COUNTER << endl;
cout << "COUNTERS::DESTRUCTOR_COUNTER = " << COUNTERS::DESTRUCTOR_COUNTER << endl;
cout << "Example count = " << Example::count() << endl;
cout << "Deep count = " << Deep::count() << endl;
cout << "Child count = " << Child::count() << endl;
}
int main()
{
for(unsigned int i=0 ; i < 10; i++)
myChildFunction();
printStatus();
return 0;
}
You are missing out on deleting some Example objects because of this line:
d.e = NULL;
in Child::Child().
You are allocating memory for e in the constructor of Deep. After executing the above line, that memory is leaked.
You can resolve that problem by:
Removing that line (or commenting it out),
Deleting d.e before making it NULL, or
Doing something else that prevents the memory leak.
Update, in response to comment
Copy constructor for Child:
Child(const Child& c) : d(c.d),
name(c.name),
age(c.age),
e(new Example(*c.e)),
list(c.list),
deep_list(c.deep_list)
{
COUNTERS::DESTRUCTOR_COUNTER++; // This is for Child
COUNTERS::NEW_COUNTER++; // This is for new Example
}
I removed all information that cluttered your code.
When using templates, constructors and copy constructors NEED the following: Example < eltType >(void);
in the class definition. All objects that inherit from Countables are known as derived classes. They also may call a derived class a child, and the class in which it is derived from is called the parent. I added the COPY_CONSTRUCTOR_COUNT to add clarification to the data which is being presented on the console/command prompt. Usually when trying to preform a task, large or small, doing it incrementally and by providing methods, for each task, saves you time and a headache. I removed the new_count and delete_count from the equation, because I felt that it was not needed.
You will notice that I added : Countable( * ((Countable < eltType > *)&e))
This is a requirement when designing a program that involves inheritance, which introduces the
topic of Polymorphism :D
What that bit of code does is that it gets a pointer of a Countable, which will point to the address of object e, which then allows access to all super classes of this class, but not including e's class.
NOTE: Since e is a derived class of Countable, this is valid statement.
For you second question, all of your data members are public, you can use an iterator to copy your data stored in you vectors.
As a concern from one programmer to another, I hope your code in practice is well documented, and all methods declared in your class are defined in a .cpp file.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class COUNTERS
{
public:
static int NEW_COUNTER;
static int DELETE_COUNTER;
static int CONSTRUCTOR_COUNTER;
static int DESTRUCTOR_COUNTER;
static int COPY_CONSTRUCTOR_COUNTER;
};
int COUNTERS::NEW_COUNTER = 0;
int COUNTERS::DELETE_COUNTER = 0;
int COUNTERS::CONSTRUCTOR_COUNTER = 0;
int COUNTERS::DESTRUCTOR_COUNTER = 0;
int COUNTERS::COPY_CONSTRUCTOR_COUNTER = 0;
/* template used for counting constructors/destructors to debug memory leaks */
template <typename T>
class Countable
{
public:
Countable<T>()
{
incrementObjectCount();
};
Countable<T>(Countable const&)
{
incrementObjectCount();
};
virtual ~Countable()
{
decrementObjectCount();
};
static unsigned count()
{
return cs_count_;
};
protected:
static unsigned cs_count_;
////////////////////////////////////ADDED////////////////////////////////////
protected:
void incrementObjectCount(void){ ++cs_count_; };
void decrementObjectCount(void){ --cs_count_; };
void incrementDeconstructorCounter(void){ ++COUNTERS::DESTRUCTOR_COUNTER; };
/////////////////////////////////////ADDED////////////////////////////////////
};
template <typename T>
unsigned Countable<T>::cs_count_ = 0;
class Example : public Countable<Example>
{
public:
Example() : Countable<Example>()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
}
virtual ~Example()
{
incrementDeconstructorCounter();
}
// copy constructor
Example(const Example& e) : Countable<Example>(*((Countable<Example>*)&e))
{
// COUNTERS::CONSTRUCTOR_COUNTER++; This is copy constructor, you addmitted this from "Child" class CCstr
++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
}
};
class Deep : public Countable<Deep>
{
public:
Deep() : Countable<Deep>()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
}
virtual ~Deep()
{
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Deep(const Deep& x) : Countable<Deep>(*((Countable<Deep>*)&x))
{
//COUNTERS::CONSTRUCTOR_COUNTER++;
++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
};
};
class Child : public Countable<Child>
{
public:
vector<Example> list;
vector<Deep> deep_list;
void init()
{
deep_list.push_back(Deep());
list.push_back(Example());
}
Child() : Countable<Child>()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
init();
}
virtual ~Child()
{
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Child(const Child& c) : Countable<Child>(*((Countable<Child>*)&c))
{
++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
}
};
void myChildFunction(){
Child* c = new Child();
//COUNTERS::NEW_COUNTER++;not needed
delete c;
//COUNTERS::DELETE_COUNTER++; not need
}
void printStatus(){
cout << "COUNTERS::NEW_COUNTER = " << COUNTERS::NEW_COUNTER << endl;
cout << "COUNTERS::DELETE_COUNTER = " << COUNTERS::DELETE_COUNTER << endl;
cout << "COUNTERS::CONSTRUCTOR_COUNTER = " << COUNTERS::CONSTRUCTOR_COUNTER << endl;
cout << "COUNTERS::DESTRUCTOR_COUNTER = " << COUNTERS::DESTRUCTOR_COUNTER << endl;
cout << "COUNTERS::COPY_CONSTRUCTOR_COUNTER = " << COUNTERS::COPY_CONSTRUCTOR_COUNTER << endl;
cout << "Example count = " << Example::count() << endl;
cout << "Deep count = " << Deep::count() << endl;
cout << "Child count = " << Child::count() << endl;
}
int main()
{
for (unsigned int i = 0; i < 10; i++)
myChildFunction();
printStatus();
system("pause");
return 0;
}
This error occurs during run time, and I'm not sure what's causing it - the code looks correct to me.
#include <iostream>
#include <string>
using namespace std;
struct Room {
int d_noSeat;
bool d_hasProjector;
Room() = default;
Room(const Room& r);
};
class Event {
Room* d_room;
std::string d_name;
public:
Event();
Event(const Event& e);
~Event();
void set(Room r, const std::string& name);
void print();
};
Event::Event() : d_room(0), d_name("") {};
void Event::print() {
std::cout << "Event: " << d_name;
if (d_room != 0) {
std::cout << " in size " << d_room->d_noSeat;
if (d_room->d_hasProjector)
std::cout << " with";
else
std::cout << " without";
std::cout << " projector";
}
std::cout << std::endl;
return;
}
void printEvent(Event e) {
e.print();
return;
}
void Event::set(Room r, const std::string& name) {
d_room = &r;
d_name = name;
}
// Room shallow copy constructor
Room::Room(const Room& r) :
d_noSeat(r.d_noSeat),
d_hasProjector(r.d_hasProjector)
{ }
// Event deep copy constructor
Event::Event(const Event& e) :
d_name(e.d_name),
d_room(new Room(*e.d_room))
{ }
// Event destructor
Event::~Event()
{
delete[] d_room;
}
int main() {
const int noLect = 5;
Room r;
Event lectures[noLect];
for (int i = 0; i < noLect; ++i) {
r.d_noSeat = i + 1;
r.d_hasProjector != r.d_hasProjector;
lectures[i].set(r, "CSI2372");
lectures[i].print();
}
std::cout << "-------------------" << std::endl;
for (int i = 0; i < noLect; ++i) {
printEvent(lectures[i]);
}
return 0;
}
The error apparently occurs at line 52 (first line in the print() function). In addition to this, the printed text displays numbers that are very large and often negative. What is causing this?
Issue
void Event::set(Room r, const std::string& name)
{
d_room = &r;
// ^
d_name = name;
}
You are referencing to the temporary object: Room r passed by value, which is destroyed at the end of the scope: }.
Instead you must reallocate the member pointer:
d_room = new Room(r);
Why it went wrong
Because you are writing C-style code in C++ classes.
In C++ we tend to:
Avoid naked pointers, prefer smart pointers:
class Event
{
std::shared_ptr<Room> d_room;
...
Event::~Event() { /* no need to delete */ }
Use constructor overloading (instead of using set-like functions after construction):
Event(Room& r, const std::string& name):
d_room(new Room(r)),
d_name(name)
{}
Pass by reference:
void set(Room& r, const std::string& name);
Avoid raw arrays, use STL facilities instead:
std::vector<Event> lectures;
// or
std::array<Event, 5> lectures;
Another issue
r.d_hasProjector != r.d_hasProjector; // checks if r.d_hasProject is not itself
You probably want
r.d_hasProjector = !r.d_hasProjector;
Complete code: link
Also, here is a must-read link about advanced C++ stuff which, I believe, will be very useful to you: http://www.parashift.com/c++-faq/
Edit: I forgot about your question:
In addition to this, the printed text displays numbers that are very large and often negative. What is causing this?
Those numbers are garbage. Variables that are not explicitly initialized are not initialized at all. Memory is allocated but holds old information from previous program. It could contain anything. When you read from uninitialized variables, you'll get this garbage. You had a pointer which was pointing to a destroyed object. So the pointer was effectively uninitialized.
Your problem is here:
void Event::set(Room r, const std::string& name) {
d_room = &r;
d_name = name;
}
The &r takes the address of an object whose lifetime ends when the function returns, resulting in undefined behaviour when you later try to access it.
If you want to use pointers, you need to allocate them dynamically:
void Event::set(Room* r, const std::string& name) {
d_room = r;
d_name = name;
}
// ...
for (int i = 0; i < noLect; ++i) {
Room* r = new Room;
r->d_noSeat = i + 1;
r->d_hasProjector != r.d_hasProjector;
lectures[i].set(r, "CSI2372");
lectures[i].print();
}
// ...
But it doesn't look like you need pointers here, you should be able to have
Room d_room;
in the Event class.