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);
}
Related
Here is my code
#include <iostream>
#include <string>
class Person {
private:
int pancakesEaten, personID;
public:
Person() {
pancakesEaten = 0;
personID = setID();
}
static int setID() {
static int currID;
return currID++; // Returns currID and then increments.
}
bool operator>=(const Person& p);
bool operator<=(const Person& p);
void askPancakesEaten();
void print();
};
bool Person::operator>=(const Person& p) {
if(this->pancakesEaten >= p.pancakesEaten) {
return true;
}
return false;
}
bool Person::operator<=(const Person& p) {
if(this->pancakesEaten <= p.pancakesEaten) {
return true;
}
return false;
}
void Person::askPancakesEaten() {
std::cout << "Please enter how many pancakes you ate: ";
std::cin >> this->pancakesEaten;
}
void Person::print() {
std::cout << this->personID;
std::cout << "Person " << this->personID << " ate " << this->pancakesEaten << " pancakes";
}
int main() {
Person people[10];
for(int i = 0; i<10; i++) {
Person currPerson;
currPerson.askPancakesEaten();
currPerson.print();
}
}
My problem is that I am trying to initialize an array for 10 Person objects, and because of my static method, it is making my static count start at 10 when I enter my for loop.
I know I could get around this easily by just changing my constructor and getting rid of setID and just using i instead, but I am curious if there is another way around it?
... but I am curious if there is another way around it.
Why are you initializing an array and don't use it in the loop then?
for(int i = 0; i<10; i++) {
people[i].askPancakesEaten();
people[i].print();
}
Besides that setID() is named a bit unfortunate confusing (getNextID() might be a better, clearer choice IMO), there's nothing wrong with that implementation as you have it.
Also it would be better to make this function private, since how those ID's are kept and managed to be unique for the class instances, is an implementation detail, which should't be publicly accessible.
#include <iostream>
class Piece {
public:
virtual char get()=0;
virtual ~Piece() {};
};
class One : public Piece {
public:
char get() { return '1'; }
};
class Two : public Piece {
public:
char get() { return '2'; }
};
class Tile {
private:
Piece* occ;
bool prs;
public:
Tile() { prs = false; }
void setOcc(Piece* p) { prs = true; occ = p; }
Piece& getOcc() { return *occ; }
bool getPrs() { return prs; }
void explicitDest() { if (prs) { delete occ; prs = false; } }
};
class Board {
private:
Tile tiles[2][2];
public:
Board() {
tiles[0][0].setOcc(new One());
tiles[0][1].setOcc(new Two());
tiles[1][1].setOcc(new One());
}
Tile getTile(int c, int r) { return tiles[c][r]; }
void move(Board* b, int c1, int r1, int c2, int r2) {
switch(b->tiles[c1][r1].getOcc().get()) {
case '1': b->tiles[c2][r2].setOcc(new One()); break;
case '2': b->tiles[c2][r2].setOcc(new Two()); break;
}
b->tiles[c1][r1].explicitDest();
}
void print() {
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
if (tiles[j][i].getPrs()) {
std::cout << tiles[j][i].getOcc().get() << " ";
} else {
std::cout << "- ";
}
}
std::cout << "\n";
}
std::cout << "\n";
}
Board* copyBoard() { return new Board(*this); }
};
int main()
{
Board* oldBoard = new Board();
std::cout << "Old board: \n";
oldBoard->print();
Board* newBoard = oldBoard->copyBoard();
std::cout << "New board: \n";
newBoard->print();
newBoard->move(newBoard, 0, 0, 1, 1);
std::cout << "Old board after move: \n";
oldBoard->print();
std::cout << "New board after move: \n";
newBoard->print();
delete[] newBoard;
}
This is an MRE to illustrate the methodology I've been using to do deep copies. It doesn't exactly work and is just to visualize how I've been doing things.
Using this example, is my method for deep copying strong? If not, what methods are available with a C++03 constraint to ensure a copy (and changes to the copy) do not reflect upon the original it's based upon?
In the code, I defined explicitDest() which is my way of explicitly (and only explicitly) calling the destructor as I need certain behavior only sometimes. Just in case people asked.
I'm not terribly familiar with copying, copy constructors, or abstract classes/methods if the code wasn't obvious.
You should implement copy constructors and copy assignment operators and take care when using new. You need one delete for each new - unless you surrender the pointer returned by new to a smart pointer. In C++03 you have std::auto_ptr that can be used to manage the memory resources for you.
Here's an example with comments inline:
#include <iostream>
#include <memory> // std::auto_ptr
#include <algorithm> // std::swap (<algorithm> in c++03, <utility> in >= c++11)
class Piece {
public:
// A virtual destructor to support deleting via base class pointer:
virtual ~Piece() {}
// You can't make constructors virtual, so add a clone()
// function for copy constuction through a base class pointer
virtual std::auto_ptr<Piece> clone() const = 0;
// renamed get() into symbol()
virtual char symbol() const = 0;
};
class One : public Piece {
public:
// Use the implicit copy constructor for One and return a (smart) pointer
// to the base class.
std::auto_ptr<Piece> clone() const {
return std::auto_ptr<Piece>(new One(*this));
}
char symbol() const { return '1'; }
};
class Two : public Piece {
public:
std::auto_ptr<Piece> clone() const {
return std::auto_ptr<Piece>(new Two(*this));
}
char symbol() const { return '2'; }
};
class Tile {
private:
std::auto_ptr<Piece> occ; // this now handles delete for you
public:
Tile() : occ(NULL) {} // default constructor
Tile(Piece* p) : occ(p) {} // put pointer in auto_ptr
// copy constructor, use the clone() function and conversion
// to bool operator below. If "o" doesn't have a Piece, initialize occ
// with an default constructed, empty, auto_ptr<Piece>.
Tile(const Tile& o) : occ(o ? o.occ->clone() : std::auto_ptr<Piece>()) {}
// ^
// |
// +--- conversion to bool in use
// copy assignment operator
Tile& operator=(const Tile& o) {
Tile tmp(o); // use the copy constructor above
occ = tmp.occ; // steal pointer from tmp
return *this;
}
// converting assignment operator
Tile& operator=(Piece* p) {
// delete the old pointer and replace it with p:
occ.reset(p);
return *this;
}
// Conversion to bool operator using std::auto_ptr's built in get()
// to tell us if we have a Piece or not.
operator bool() const { return occ.get() != NULL; }
// Add a symbol() function to hide the logic to determine if this Tile
// has a Piece or not.
char symbol() const {
// Check if there is a Piece in this Tile using the conversion
// to bool operator here too:
if(*this)
return occ->symbol();
else
return '-'; // no Piece here
}
};
// add support to stream a Tile to an ostream
std::ostream& operator<<(std::ostream& os, const Tile& t) {
return os << t.symbol();
}
class Board {
private:
Tile tiles[2][2];
public:
Board() {
// using the added operator() further down
(*this)(0,0) = new One;
(*this)(0,1) = new Two;
(*this)(1,1) = new One;
}
// Note that cols and rows in arrays are usually seen as reversed.
// tiles[2][2] usually means:
// tiles[<rows>=2][<cols>=2]
// getTile() replacements - the interface here is still (col, row)
// but it accesses the tiles[][] using the common form (row, col)
Tile& operator()(int c, int r) { return tiles[r][c]; }
Tile const& operator()(int c, int r) const { return tiles[r][c]; }
// moving by swapping tiles
void move(int c1, int r1, int c2, int r2) {
// using operator() and the standard function std::swap
std::swap((*this)(c1, r1), (*this)(c2, r2));
}
};
// Add a stream operator to not have to call print() explicitly when streaming
std::ostream& operator<<(std::ostream& os, const Board& b) {
for(int r = 0; r < 2; r++) {
for(int c = 0; c < 2; c++) {
// Use "Board::operator() const" and stream support for returned
// Tile.
os << b(c, r);
}
os << '\n';
}
os << '\n';
return os;
}
int main() {
// no need to "new" anything:
Board oldBoard;
Board newBoard(oldBoard); // use copy constructor
// use streaming operators
std::cout << "Old board: \n" << oldBoard;
std::cout << "New board: \n" << newBoard;
// using the getTile() replacement, Board::operator():
std::cout << "New board # tile 1,0: " << newBoard(1, 0) << " before move\n";
newBoard.move(0, 0, 1, 0);
std::cout << "New board # tile 1,0: " << newBoard(1, 0) << " after move\n\n";
std::cout << "New board after move:\n" << newBoard;
newBoard = oldBoard; // copy assignment operator
std::cout << "New board after reinit:\n" << newBoard;
}
Be aware of that there are many things inside example that would be done in a slightly different (more efficient) way in C++11 and later where std::unique_ptr, move semantics and extended initializer lists were added.
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.
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.