I have a class School like this. Space is an abstract class, don't mind about it.
class school:public space
{
private:
schoolyard y;
stairs s;
floor floors[3];
int capa;
public:
school(int x):floors[1](x),floors[2](x),floors[3](x){
cout<<"a school has been created"<<endl;}
void move(student x);
~school();
};
floor is another class which I want to initialize. This part floors[1](x),floors[2](x),floors[3](x) is probably wrong. Maybe someone know how I can initialize an array of objects in a class?
Should be:
school(int x) : floors{x, x, x}
{
std::cout << "a school has been created" << std::endl;
}
First off, arrays are 0-based, so the valid indexes are 0-2, not 1-3.
Second, you can't initialize individual array members in a constructor's member initialization list like you are attempting to.
If floor does not have a default constructor, you can change your floors[] array to hold floor* pointers instead, and then construct each floor object using new in the constructor's body, eg:
class school : public space
{
private:
...
floor* floors[3];
...
public:
school(int x){
for (int i = 0; i < 3; ++i){
floors[i] = new floor(x);
}
// other initialization as needed...
cout << "a school has been created" << endl;
}
~school(){
for (int i = 0; i < 3; ++i){
delete floors[i];
}
}
...
};
Be aware that with this approach, you need to follow the Rule of 3/5/0, which means also implementing a copy constructor and a copy assignment operator, and optionally a move constructor and a move assignment operation in C++11 and later:
...
#include <algorithm>
class school : public space
{
private:
...
floor* floors[3];
...
public:
school(int x){
for (int i = 0; i < 3; ++i){
floors[i] = new floor(x);
}
// other initializations as needed...
cout << "a school has been created" << endl;
}
school(const school &src){
for (int i = 0; i < 3; ++i){
floors[i] = new floor(*(src.floors[i]));
}
// other copies as needed...
cout << "a school has been copied" << endl;
}
school(school &&src){
for (int i = 0; i < 3; ++i){
floors[i] = src.floors[i];
src.floors[i] = nullptr;
}
// other moves as needed...
cout << "a school has been moved" << endl;
}
~school(){
for (int i = 0; i < 3; ++i){
delete floors[i];
}
}
school& operator=(const school &rhs){
if (this != &rhs){
school temp(rhs);
std::swap_ranges(floors, floors+3, temp.floors);
}
return *this;
}
school& operator=(school &&rhs){
school temp(std::move(rhs));
std::swap_ranges(floors, floors+3, temp.floors);
return *this;
}
...
};
However, a std::vector would make things much easier, letting the compiler handle all of these details for you, eg:
...
#include <vector>
class school : public space
{
private:
...
std::vector<floor> floors;
...
public:
school(int x): floors(3, floor(x)) {
cout << "a school has been created" << endl;
}
...
};
Related
#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.
I have class XOBoard that present an array that is size n*n,each cell of the array is an Object called Cell.
Each Cell object is defined by
class Cell {
private:
char ch;
public:
Cell(char ch = '.');
char getCellValue();
void setCellValue(char nch);
};
Board is defined this way:
class XOBoard {
private:
int n;
Cell **Board;
};
XOBoard::XOBoard(int n) { //constructor
this->n = (n >= 3) ? n : 3;
Board = new Cell*[n];
for (int i = 0; i < n; i++) {
Board[i] = new Cell[n];
}
}
I wanted to get to a specific Cell value by using this method: board1[{1,2}], but I want to check if the values that sent to me is withing the range(n), but unfortantly I was unable to get to the Board array, and to n variable.
Here is the code:
XOBoard& operator[](list<int> list){
int x = list.front(), y = list.back();
return Board[x][y].getCellValue();
}
Thanks a head!
As mentioned in the comments, using operator[] for multidimensional subscripting is unconventional, but if you want that, you should make sure you get the correct amount of values (2 in this case) and that you return the correct type (a Cell& in this case).
Also be aware of shadowing. If you try to construct a Board with a value less than 3, you'll set this->n to 3 but go on with the construction using the erroneous n (that may even be a negative value).
More comments inline:
#include <iostream>
#include <stdexcept>
#include <tuple>
class Cell {
private:
char ch;
public:
Cell(char nch = '.') : // after the colon comes the member initializer list
ch(nch) // which is usually good to use
{
// if(ch is not valid) throw ...
}
char getCellValue() const { return ch; }
// a convenient conversion operator to automatically
// convert a Cell to a char where a char is needed
// (like when streaming a Cell to std::cout)
operator char() const { return ch; }
// void setCellValue(char nch); // replaced by operator=
Cell& operator=(char nch) {
// if(nch is not valid) throw ...
ch = nch;
return *this;
}
};
class XOBoard {
private:
size_t n; // use an unsigned type for sizes/indices
Cell** Board;
public:
// constructor
XOBoard(size_t xy_size) : // a member initializer list again
n(xy_size >= 3 ? xy_size : 3), // assign to "n" here
Board(new Cell*[n]) // the correct n is now used
{
// if the below construction fails, a bad_alloc will be thrown.
// you need to add code to clean up what you've already allocated to take
// care of that situation.
for(size_t i = 0; i < n; i++) {
Board[i] = new Cell[n];
}
}
// Copying or moving need careful handling of the pointers.
// Read "The rule of three/five/zero". Until then, disable it.
XOBoard(const XOBoard&) = delete;
XOBoard& operator=(const XOBoard&) = delete;
// destructor
~XOBoard() {
for(size_t i = 0; i < n; i++) delete[] Board[i];
delete[] Board;
}
// added for convenience
size_t size() const { return n; }
// return a Cell& and use a std::pair since you
// expect exactly 2 values
Cell& operator[](std::pair<size_t, size_t> pos) {
auto& [x, y] = pos;
if(x>=n || y>=n)
throw std::out_of_range("{"+std::to_string(x)+","+std::to_string(y)+"}");
return Board[x][y];
}
};
int main() {
try {
XOBoard a{2}; // trying an invalid size
std::cout << a.size() << '\n';
a[{2, 2}] = 'a';
std::cout << a[{2, 2}] << '\n';
Cell x = 'b';
a[{2, 2}] = x;
std::cout << a[{2, 2}] << '\n';
a[{2, 3}] = 'c'; // index out of bounds
} catch(const std::out_of_range& ex) {
std::cerr << "out_of_range exception: " << ex.what() << '\n';
}
}
Output:
3
a
b
out_of_range exception: {2,3}
You should try to avoid raw pointers and actual multidimensional arrays. It's often better to emulate dimensionality by allocating a 1d array and provide an interface to the user that calculates the correct element to work on.
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;
}
I am little lost with templates, and how compiler processes them.
Needed some generic wrapper for std::vector<< SomeType * >>* lpVars; that is capable of performing delete on all items contained inside that vector when I delete lpVars. Something similar to the C#'s List<> (generic list class).
So I went for templates and wrote something like this:
template<class T>
class ListPtr
{
public:
std::vector<T*> items;
ListPtr()
{ }
~ListPtr()
{
size_t count = items.size();
for(size_t i=0; i<count; i++)
{
T* item = items[i];
delete item;
}
items.clear();
}
inline const int count() const
{
return (int)items.size();
}
inline T* operator[](size_t index) const
{
return items[index];
}
inline void Add(T* item)
{
items.push_back(item);
}
};
later on I declared global type lists like:
class SomeType1List : public ListPtr<SomeType1> {};
class SomeType2List : public ListPtr<SomeType2> {};
...
class SomeTypeNList : public ListPtr<SomeTypeN> {};
Here is the first part of my interest on subject:
(1) Are this classes SomeType1List, SomeType1List, ..., SomeTypeNList fully preprocessed to templates code with replaced T template type for each declaration (SomeType1, SomeType2, ..., SomeTypeN) like there is no template (are fully declared classes), or compiler performs some other magic here?
(2) And if compiler performs some other magic, how should I define this types that compiler would compile them as they are fully declared classes?
To explain usage of above code more precise:
this list instances are initialized, and returned from functions like following one:
SomeType1List* GetItems()
{
SomeType1List* items = new SomeType1List();
for(int i=0; i<1000; i++)
{
SomeType1* item = new SomeType1();
// feed item with some data
items->Add(item);
}
return items;
}
and used in other parts of code like this:
SomeType1List* items = GetItems();
int count = items->count();
for(int i=0; i<count; i++)
{
SomeType1* item = items[i];
// do something with item;
}
delete items; // all memory occupied by items released after this line
Second part of my interest on subject:
(3) Could this be written differently using only standard classes (no boost or similar sdks)? goal is speed but to keep code clean and easy to read. So this question would be is there any better way to do all of this?
Yes
No magic here
You can use std::vector<std::unique_ptr<T>> (C++11) or std::vector<std::auto_ptr<T>> (kind of deprecated)
Example:
#include <iostream>
#include <memory>
#include <vector>
class T
{
private:
unsigned int _i;
public:
void print() const
{
std::cout << "Print: " << _i << std::endl;
}
T(unsigned int i)
{
_i = i;
std::cout << "Constructor! " << _i << std::endl;
}
~T()
{
std::cout << "Destructor! " << _i << std::endl;
}
};
std::vector<std::unique_ptr<T>>* createStuff()
{
auto output = new std::vector<std::unique_ptr<T>>;
for(unsigned int i = 0; i < 5; i++)
{
output->emplace_back(new T(i));
}
return output;
}
int main()
{
std::cout << "Begin!" << std::endl;
auto stuff = createStuff();
for(std::unique_ptr<T> const& thing : *stuff)
{
thing->print();
}
delete stuff;
std::cout << "End!" << std::endl;
return 0;
}
Output:
Begin!
Constructor! 0
Constructor! 1
Constructor! 2
Constructor! 3
Constructor! 4
Print: 0
Print: 1
Print: 2
Print: 3
Print: 4
Destructor! 0
Destructor! 1
Destructor! 2
Destructor! 3
Destructor! 4
End!