C++ pool allocator program crashing only on console close - c++

I am looking at this pool allocator implementation. I have actually modified it a bit and my full code is:
template <class T, size_t T_per_page = 200>
class PoolAllocator
{
private:
const size_t pool_size = T_per_page * sizeof(T);
std::vector<T *> pools;
size_t count;
size_t next_pos;
void alloc_pool() {
next_pos = 0;
void *temp = operator new(pool_size);
pools.push_back(static_cast<T *>(temp));
}
public:
PoolAllocator() {
count = 0;
alloc_pool();
}
void* allocate() {
if (next_pos == T_per_page)
alloc_pool();
void* ret = pools.back() + next_pos;
++next_pos;
++count;
return ret;
}
size_t getSize() const
{
return T_per_page * (pools.size() - 1) + next_pos;
}
size_t getCount() const
{
return count;
}
size_t getCapacity() const
{
return T_per_page * pools.size();
}
T* get(size_t index) const
{
if (index >= getCount()) { return NULL; }
size_t poolIndex = index / T_per_page;
return pools[poolIndex] + (index % T_per_page);
}
~PoolAllocator() {
std::cout << "POOL ALLOCATOR DESTRUCTOR CALLED" << std::endl;
while (!pools.empty()) {
T *p = pools.back();
size_t start = T_per_page;
if (pools.size() == 1){
start = next_pos;
}
std::cout << "start: " << start << std::endl;
for (size_t pos = start; pos > 0; --pos)
{
std::cout << "pos: " << pos << std::endl;
p[pos - 1].~T();
}
operator delete(static_cast<void *>(p));
pools.pop_back();
}
}
};
template<class T>
PoolAllocator<T>& getAllocator()
{
static PoolAllocator<T> allocator;
return allocator;
}
class Node
{
private:
int id;
std::vector<float> vertices;
public:
Node() : id(42)
{
std::cout << "Node constructor called" << std::endl;
}
~Node(){ std::cout << "Node destructor called" << std::endl; }
void* operator new(size_t size)
{
std::cout << "Node operator new called" << std::endl;
return getAllocator<Node>().allocate();
}
void operator delete(void*)
{
std::cout << "Node operator delete called" << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
Node* n1 = new Node();
Node* n2 = new Node();
Node* n3 = new Node();
Node* n4 = new Node();
std::cout << "Count: " << getAllocator<Node>().getCount() << " size: " << getAllocator<Node>().getSize() << " capacity: " << getAllocator<Node>().getCapacity() << std::endl;
while (true){}
return 0;
}
When I run this code in visual studio it appears to work correctly up until I close the console at which point I get an access violation error. I have tried manually calling the destructor on the allocator and it appears to work properly but I must be making a mistake somewhere. The error I get is:
Can anyone spot where I am making my mistake?
Edit 1:
Upon further investigation it will still crash even without the new Node lines in main. Seems to be related to getAllocator() method and how the destructor is called maybe? Or the fact that the allocator is static??
Edit 2:
I actually don't think it has anything to do with my allocator at all! If I try the code:
class Node2
{
private:
int x;
public:
Node2():x(42){std::cout << "Node2 constructor called" << std::endl;};
Node2(const Node2& other){ std::cout << "Node2 copy constructor called" << std::endl; };
~Node2(){ std::cout << "Node2 destructor called" << std::endl; };
};
Node2& Test(){
static Node2 myIndex;
return myIndex;
}
int _tmain(int argc, _TCHAR* argv[])
{
Test();
while (true){}
return 0;
}
It results in the same error! The plot thickens. I assumed being new to writing custom allocators that the allocator code was the issue. Still not sure why exactly this error is happening for my smaller code yet...

Writing an answer as I can't comment on the question.
I can't spot any obvious error in the last code. Are you sure you are compiling the right file and not an old unsaved version and such?
You can try to remove the line
while (true){}
And let the program just end normally.
Also, you can try to run your code in debug mode, single-stepping the instructions to find the one causing troubles.

I can spot some problems with that pool allocator.
PoolAllocator owns resources, but there's neither special copy constructor nor assignment. Most likely you should declare them deleted. And provide move-constructor and move-assignment. Though not a factor in this particular example, it may protect you from absendmindedly returning an allocator by value.
Function alloc_pool() resets next_pos before the new chunk is allocated. An exception, if ever thrown by operator new, would leave the pool in an inconsistent state.
Likewise, an exception in pools.push_back() would see the new chunk leaked. I believe std::vector<std::vector<std::byte>> would do just right, what with modern vectors being moveable. But if you absolutely want to use a vector of raw pointers, you should reserve extra space in pools, then allocate new chunk, and only then call push_back and modify the state.
Constructor of PoolAllocator may throw for no good reason.
Since allocate() method have to call alloc_pool() anyway, why calling it in the constructor? You could have a trivial noexcept constructor simply by leaving all allocation work to allocate().
PoolAllocator::allocate() and PoolAllocator::~PoolAllocator() are not symmetric. The former returns raw memory with no initialized object, while the latter assumes there's a properly constructed object in every allocated slot. That assumption is dangerous and very fragile. Imagine, for example, that T::T() throws.
It seems that getSize() and getCount() always return the same value. Is it intended?
Destructor will delete next_pos objects in the first pool, pools[0], and T_per_page objects in every other pool. But it should delete next_pos objects in the last pool.
You're in for wonderful bugs if T:~T() called from destructor of the pool ever tried to allocate another object from that very same pool. Such scenario may seem weird, but well, technically it can happen. Destructor'd better swap the current state of the pool to local variables and work on them. Repeating, if necessary.
That infinite loop in main() could spoil the destruction of global objects. Compiler could be smart enough to figure out that return is unreachable and skip the destruction part altogether.
pool_size could be a static member.

Related

Creating a dynamic array to hold a custom struct without accidentally deconstructing the items

My question is summed up pretty well with this code snippet:
struct T {
int* heapValue;
T(){
this->heapValue = new int[3]; // any dynamic size
}
~T(){
delete[] this->heapValue;
}
}
int main() {
int N = 5; // some value determined at runtime
T* array = new T[N];
for (int i = 0; i < N; i++)
{
T t = T(123, 456, args);
t.do_something();
array[i] = t;
} // uh oh, t is deconstructed! and array[i].heapValue is invalidated
int x = array[0].heapValue[0]; // segfault
}
I was able to solve this by creating T** array instead and making each t with new T(args), but then when it comes time to deallocate array I need to loop through each element and delete it first before deleting the array itself. This is slow and inconvenient. Also, T** looks like a 2-dimensional array which is potentially misleading.
The same issue occurs with std::vector<T> and can be solved with the equally slow and inconvenient std::vector<T*>.
Is there any way to create a dynamic array T* such that the elements are not deconstructed right after being assigned?
The comments under your questions already summed up all the possibilities to handle this problem. Anyway, here is quick example how to use move semantics, with minimal changes to your code:
struct T {
int* heapValue;
T(){
std::cout << "CTOR: " << this << std::endl;
this->heapValue = new int[3]; // any dynamic size
}
~T(){
std::cout << "DTOR: " << this << std::endl;
delete[] this->heapValue;
}
T(const T& other) = delete;
T& operator=(const T& other) = delete;
T& operator=(T&& other)
{ // this can be more simple if you decide to use std::unique_ptr to hold your heapValue
delete[] this->heapValue;
this->heapValue = other.heapValue;
other.heapValue = nullptr;
return *this;
}
T(T&& other)
{
*this = std::move(other); // to avoid duplicate code
}
void do_something(){
std::cout << "do_something: " << this << std::endl;
heapValue[0]= 123; // just for demonstration
heapValue[1]= 456;
heapValue[2]= 789;
}
};
int main() {
int N = 5; // some value determined at runtime
T* array = new T[N];
for (int i = 0; i < N; i++)
{
T t = T();
t.do_something();
array[i] = std::move(t);
}
std::cout << array[0].heapValue[0] << std::endl;
std::cout << array[0].heapValue[1] << std::endl;
std::cout << array[0].heapValue[2] << std::endl;
}
By deleting copy constructor and assignment we make sure there will be no invalid memory access. By providing move assignment we have a cheap way of storing your objects in the array.
Is there any way to create a dynamic array T* such that the elements are not deconstructed right after being assigned?
Yes, but it's far less efficient than just using T** or std::vector<T*> though.
Basically, I needed to add a copy constructor T(const T& other) so that a second T could be created on the heap and copied from the stack instance, then the stack instance could safely be deconstructed. This document describes the rule of three that some commenters were talking about.
However, this is quite inefficient because two instances must be constructed (and one destructed), which is not ideal.
In conclusion, it's likely better to just use an array of pointers like so:
T** arr = new T*[size];
for (int i = 0; i < size; i++)
{
arr[i] = new T(args);
}
Of course you can also use a std::vector<std::unique_ptr<T>> or some other combination, but the idea is to allocate the T instances on the heap from the get-go.
In this line
T t = T(123, 456, args);
you are creating a local variable, which quickly goes out of scope, so the pointer you are trying to use is invalidated, try allocating in loop with new

Is it possible to overload delete operator to set the pointer to null?

What I want to do is overload the delete operator for my class to automatically set the pointer to null after deleting it so I can safe delete it inside a member function, like that:
# include <iostream>
class Buddy
{
public:
Buddy(void) : _hp(100) { }
~Buddy(void) { std::cout << "Buddy is dead!" << std::endl; }
void operator delete(void * ptr)
{
::delete (Buddy*)ptr;
ptr = nullptr;
}
void getDamage(int amount)
{
_hp -= amount;
if (_hp <= 0)
delete this;
}
private:
int _hp;
};
void hitBuddy(Buddy *buddy)
{
if (!buddy)
std::cout << "Buddy is already dead!" << std::endl;
else
{
std::cout << "Hitting buddy!" << std::endl;
buddy->getDamage(70);
}
}
int main(void)
{
Buddy *dude = new Buddy;
hitBuddy(dude);
hitBuddy(dude);
hitBuddy(dude);
return (0);
}
But it doesn't set the pointer to null and it calls two times the destructor, is there a proper way to set the pointer to null inside the class like I want to do?
(OUTPUT)
Hitting buddy!
Hitting buddy!
Buddy is dead!
Buddy is dead!
Hitting buddy!
Buddy is dead!
Buddy is dead!
a.out(79480,0x10d3cbdc0) malloc: *** error for object 0x7fe345c05790: pointer being freed was not allocated
a.out(79480,0x10d3cbdc0) malloc: *** set a breakpoint in malloc_error_break to debug
[1] 79480 abort ./a.out
No. It is not possible to overload operator delete so that it sets the pointer to null.
This is because the standard requires the first parameter to operator delete (which is the pointer to be deleted) to have type void* and thus the operator delete only receives a copy of the pointer and cannot modify the original argument. It cannot have type void*&. (In C++20, "destroying delete" is supported, in which case the parameter shall have type C* but still no references are allowed.)
The implementation is allowed to zero out pointers after a delete-expression as a technique to help the programmer catch use-after-free bugs but there is no way to do this yourself.
With smart ptr abuse, you might do:
class Buddy
{
Buddy() = default;
Buddy(const Buddy&) = delete;
Buddy& operator=(const Buddy&) = delete;
public:
~Buddy() { std::cout << "Buddy is dead!" << std::endl; }
void getDamage(int amount)
{
_hp -= amount;
if (_hp <= 0)
self.reset();
}
static std::weak_ptr<Buddy> make() { auto p = new Buddy; return p->self; }
private:
int _hp = 100;
std::shared_ptr<Buddy> self{this};
};
void hitBuddy(std::weak_ptr<Buddy> buddy_weak)
{
auto buddy = buddy_weak.lock();
if (!buddy) {
std::cout << "Buddy is already dead!" << std::endl;
} else {
std::cout << "Hitting buddy!" << std::endl;
buddy->getDamage(70);
}
}
int main()
{
std::weak_ptr<Buddy> dude = Buddy::make();
hitBuddy(dude);
hitBuddy(dude);
hitBuddy(dude);
}
Demo
is there a proper way to set the pointer to null inside the class
like I want to do?
No, it is neither possible nor helpful.
This
void operator delete(void * ptr)
{
::delete (Buddy*)ptr;
ptr = nullptr;
}
does not work because the function receives ptr by value, so ptr = nullptr; only modifies the local copy.
Even if it was possible, it would not help if Buddy is not created by new. And would be a terrible design in any case.

Constructors and Advanced Exception Throwing C++

I have to analyze this C++ code which involves exceptions, but I’m not used to analyzing what code is supposed to do. There’s several things about it I don’t understand. Additionally, I don’t have experience with a buffer data structure or advanced details of throwing exceptions in C++.
What is the max size of the data structure?
That is to say, if a Seq_Buffer is made with size_ = 100, how many
elements can be stored?
My intuition tells me that if you create something with size 100,
it’s max size will be 100, but I can’t be sure with facts.
Constructors can throw exceptions in c++?
Can the constructor for Seq_Buffer throw an exception?
Assuming this is true, why does that work without explicating
stating a try, catch, or throw block? I thought that was the only way to get exceptions
I’ve tried searching for these two questions, but I’m really quite lost. Thank you for taking the time to read.I’ve tried searching for these two questions, but I’m really quite lost. Thank you for taking the time to read.
The code for the Seq_Buffer class with its constructor is below:
#ifndef SEQBUFFER_H
#define SEQBUFFER_H
#include <memory>
#include <experimental/optional>
#include "optional.h"
// Exceptions classes
struct full_buffer {};
struct empty_buffer {};
// Sequential buffer for values of type T
template <typename T>
class seq_buffer {
public:
// Constructs a buffer for n elements
seq_buffer(int n) :
size_{n},
buf_{new item_type[size_]}
{
}
// Default destructor
~seq_buffer() = default;
// Size of buffer
int size() const noexcept {
return size_;
}
// Is buffer empty?
bool empty() const noexcept {
return next_read_ == next_write_;
}
// Is buffer full?
bool full() const noexcept {
const int next = next_position(next_write_);
return next == next_read_;
}
// Put element x into buffer with marker last.
// An empty element signals end of buffer.
void put(const optional<T> & x);
// Gets a pair with next element and last indication.
// Pair is accessed through members first and second
optional<T> get();
private:
// Compute next position after p following circular order
int next_position(int p) const noexcept {
return p + ((p+1>=size_)?(1-size_):1);
}
private:
// Size of buffer
const int size_;
using item_type = optional<T>;
// Unique pointer to buffer of size_ elements.
std::unique_ptr<item_type[]> buf_;
// Next position to read
int next_read_ = 0;
// Next position to write
int next_write_ = 0;
};
template <typename T>
void seq_buffer<T>::put(const optional<T> & x)
{
const int next = next_position(next_write_);
if (next == next_read_) throw full_buffer{};
if (!x) {
buf_[next_write_] = {};
}
else {
buf_[next_write_] = *x;
}
next_write_ = next;
}
template <typename T>
optional<T> seq_buffer<T>::get()
{
if (empty()) throw empty_buffer{};
auto res = buf_[next_read_];
next_read_ = next_position(next_read_);
return res;
}
#endif
Yes we can throw exceptions from constructors.It is the best way of dealing with constructor failures or class initialization error.Take this code example
class bar
{
public:
bar()
{
std::cout << "bar() called" << std::endl;
}
~bar()
{
std::cout << "~bar() called" << std::endl;
}
};
class foo
{
public:
foo()
: b(new bar())
{
std::cout << "foo() called" << std::endl;
throw "throw something";
}
~foo()
{
delete b;
std::cout << "~foo() called" << std::endl;
}
private:
bar *b;
};
int main(void)
{
try {
std::cout << "heap: new foo" << std::endl;
foo *f = new foo();
} catch (const char *e) {
std::cout << "heap exception: " << e << std::endl;
}
try {
std::cout << "stack: foo" << std::endl;
foo f;
} catch (const char *e) {
std::cout << "stack exception: " << e << std::endl;
}
return 0;
}
Here you are throwing exception from the constructor itself.But there are situations where you allocate memory(heap) in the constructor.In those situation it is not much useful to throw exception in the constructor as this will lead to memory leak.Because if the class fails to initialize then there will be no destructor called for the class as there is already exception thrown(assuming that in the destructor the allocated memory is freed using free).So throwing exception in constructor depends on the scenario or the use case.Not every situation benefits from throwing exception in the constructor.

Delete array of classes without calling destructors

Consider we create the array using this way:
T* arr = new T[num];
And now because of some reasons we understood that we need simply delete that array but without calling any T destructors.
We all know that if we write next:
delete arr;
the T destructor will be called.
If we write this:
delete[] arr;
the num destructors would be called.
Having played with pointers, you realize that new inserts before the result pointer the unsigned long long value that represents the number of allocated T instances. So we try to outwit the C++ trying to change that value to number of bytes that arr occupies and delete it as (char*) in hope that in this case the delete would not call the destructors for T instances and simply free occupied memory. So you write something like this:
typedef unsigned long long;
unsll & num = *(unsll)((char*)arr-sizeof(unsll));
num = num*sizeof(T);
delete ((char*)arr);
But that doesn't work and C++ creates the trigger breakpoint(run time error) when trying to delete this. So that doesn't work. And a lot of other playing with pointers doesn't work as at least some error(compile- or run-time) occurs. So the question is:
Is that possible to delete an array of classes in C++ without calling their destructors?
Perhaps you want ::operator delete[](arr).
(See http://en.cppreference.com/w/cpp/memory/new/operator_delete)
But this still has undefined behaviour, and is a terrible idea.
One simple way to deallocate without calling destructors is to separate allocation and initialization. When you take proper care of alignment you can use placement new (or the functionality of a standard allocator object) to create the object instances inside the allocated block. Then at the end you can just deallocate the block, using the appropriate deallocation function.
I can't think of any situation where this would be a smart thing to do: it smells strongly of premature optimization and X/Y-problem (dealing with problem X by imagining impractical Y as a solution, then asking only about Y).
A new-expression is designed to couple allocation with initialization, so that they're executed as an all-or-nothing operation. This coupling, and ditto coupling for cleanup and deallocation, is key to correctness, and it also simplifies things a lot (i.e., inside there's complexity that one doesn't have to deal with). Uncoupling needs to have a very good reason. Avoiding destructor calls, for e.g. purposes of optimization, is not a good reason.
I'm only going to address your specific question of
Is that possible to delete an array of classes in C++ without calling their destructors?
The short answer is yes.
The long answer is yes, but there's caveats and considering specifically what a destructor is for (i.e. resource clean up), it's generally a bad idea to avoid calling a class destructor.
Before I continue the answer, it should be noted that this is specifically to answer your question and if you're using C++ (vs. straight C), using this code will work (since it's compliant), but if you're needing to produce code in this way, you might need to rethink some of your design since code like this can lead to bugs/errors and general undefined behavior if not used properly.
TL;DR if you need to avoid destructors, you need to rethink your design (i.e. use copy/move semantics or an STL container instead).
You can use malloc and free to avoid constructor and destructor calls, example code:
#include <iostream>
#include <cstdio>
class MyClass {
public:
MyClass() : m_val(0)
{
this->init(42);
std::cout << "ctor" << std::endl;
}
~MyClass()
{
std::cout << "dtor" << std::endl;
}
friend std::ostream& operator<<(std::ostream& stream, const MyClass& val)
{
stream << val.m_val;
return stream;
}
void init(int val)
{
/* just showing that the this pointer is valid and can
reference private members regardless of new or malloc */
this->_init(val);
}
private:
int m_val;
void _init(int val)
{
this->m_val = val;
}
};
template < typename Iterator >
void print(Iterator begin, Iterator end)
{
while (begin != end) {
std::cout << *begin << std::endl;
++begin;
}
}
void set(MyClass* arr, std::size_t count)
{
for (; count > 0; --count) {
arr[count-1].init(count);
}
}
int main(int argc, char* argv[])
{
std::cout << "Calling new[10], 10 ctors called" << std::endl;
MyClass* arr = new MyClass[10]; // 10 ctors called;
std::cout << "0: " << *arr << std::endl;
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling delete[], 10 dtors called" << std::endl;
delete[] arr; // 10 dtors called;
std::cout << "Calling malloc(sizeof*10), 0 ctors called" << std::endl;
arr = static_cast<MyClass*>(std::malloc(sizeof(MyClass)*10)); // no ctors
std::cout << "0: " << *arr << std::endl;
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling free(), 0 dtors called" << std::endl;
free(arr); // no dtors
return 0;
}
It should be noted that mixing new with free and/or malloc with delete results in undefined behavoir, so calling MyClass* arr = new MyClass[10]; and then call free(arr); might not work as "expected" (hence the UB).
Another issue that will arise from not calling a constructor/destructor in C++ is with inheritance. The above code will work with malloc and free for basic classes, but if you start to throw in more complex types, or inherit from other classes, the constructors/destructors of the inherited classes will not get called and things get ugly real quick, example:
#include <iostream>
#include <cstdio>
class Base {
public:
Base() : m_val(42)
{
std::cout << "Base()" << std::endl;
}
virtual ~Base()
{
std::cout << "~Base" << std::endl;
}
friend std::ostream& operator<<(std::ostream& stream, const Base& val)
{
stream << val.m_val;
return stream;
}
protected:
Base(int val) : m_val(val)
{
std::cout << "Base(" << val << ")" << std::endl;
}
void _init(int val)
{
this->m_val = val;
}
int m_val;
};
class Child : public virtual Base {
public:
Child() : Base(42)
{
std::cout << "Child()" << std::endl;
}
~Child()
{
std::cout << "~Child" << std::endl;
}
void init(int val)
{
this->_init(val);
}
};
template < typename Iterator >
void print(Iterator begin, Iterator end)
{
while (begin != end) {
std::cout << *begin << std::endl;
++begin;
}
}
void set(Child* arr, std::size_t count)
{
for (; count > 0; --count) {
arr[count-1].init(count);
}
}
int main(int argc, char* argv[])
{
std::cout << "Calling new[10], 20 ctors called" << std::endl;
Child* arr = new Child[10]; // 20 ctors called;
// will print the first element because of Base::operator<<
std::cout << "0: " << *arr << std::endl;
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling delete[], 20 dtors called" << std::endl;
delete[] arr; // 20 dtors called;
std::cout << "Calling malloc(sizeof*10), 0 ctors called" << std::endl;
arr = static_cast<Child*>(std::malloc(sizeof(Child)*10)); // no ctors
std::cout << "The next line will seg-fault" << std::endl;
// Segfault because the base pointers were never initialized
std::cout << "0: " << *arr << std::endl; // segfault
set(arr, 10);
print(arr, arr+10);
std::cout << "0: " << *arr << std::endl;
std::cout << "Calling free(), 0 dtors called" << std::endl;
free(arr); // no dtors
return 0;
}
The above code is compliant and compiles without error on g++ and Visual Studio, but due to the inheritance, both crash when I try to print the first element after a malloc (because the base class was never initialized).
So you can indeed create and delete an array of objects without calling their constructors and destructors, but doing so results in a slew of extra scenarios you need to be aware of and account for to avoid undefined behavior or crashes, and if this is the case for your code, such that you need to ensure the destructors are not called, you might want to reconsider your overall design (possibly even use an STL container or smart pointer types).
Hope that can help.

Unusual memory leak in queue - code hangs on exit

i need to create queue of classes to be processed by a thread afterwards. The problem is that every time i add a reference to an object, queue assigns memory for that class causing huge memory leaks. This also leads to program hang on exit.
Adding 12345678 references to an object of TaskClass to TaskQueue causes 137MB memory leak.
Notice that memory is not freed when calling queue.pop().
class TaskQueue:
template <class tjob>
class TaskQueue
{
private:
std::queue<tjob> _taskqueue;
public:
TaskQueue()
{
//constructor goes here
}
//add task to queue
template < typename Class>
bool AddTask( Class &PClass)
{
_taskqueue.push(PClass);
return true;
}
bool ProcessQueue()
{
while (!_taskqueue.empty())
{
_taskqueue.front().run();
_taskqueue.pop();
}
return true;
}
//run a function pointer
template < typename Task >
bool RunTask( Task task){
task();
return true;
}
//call class entry point member .run
template < typename Class>
bool RunClass ( Class& PClass){
PClass.run();
return true;
}
//return remaining tasks
int GetRemainingTasks(){
return _taskqueue.size();
}
};
class TaskClass:
class TaskClass
{
protected:
int *ptr_x;
public:
TaskClass() {
std::cout << "TaskClass Constructor called\n";
ptr_x = new int(0);
}
bool run(){
*ptr_x = *ptr_x + 1;
return true;
}
bool printx(){
std::cout << "x is now " << *ptr_x << std::endl;
return true;
}
~TaskClass(){
//std::cout << "TaskClass destructor called!\n";
}
};
main:
int main()
{
TaskClass job1;
int nojobs = 12345678;
TaskQueue<TaskClass> TestQueue;
std::cout << "Preparing Queue... Adding " << nojobs << " tasks.. "; //std::cin.get();
for (int i=0;i<nojobs;i++)
TestQueue.AddTask(job1);
std::cout << "Done!\n"; //std::cin.get();
std::cout << "Processing Queue... ";
TestQueue.ProcessQueue();
std::cout << "Done!\n";
job1.printx();
std::cout << "Remaining tasks: " << TestQueue.GetRemainingTasks() << std::endl;
//std::cin.get();
//exit(0);
return 0;
}
The memory leak is
ptr_x = new int(0);
because you never delete that memory. At a minimum, you need to delete it in the destructor, and also add a copy constructor which deep-copies it.
A better solution is to replace the pointer with a simple
class TaskClass
{
protected:
int x;
(although I don't see why it would be static as in billz's answer).
Incidental infelicities:
unnecessary templating:
template < typename Class>
bool AddTask( Class &PClass) {
the only valid type for Class is the class template argument tjob, so why template this method at all? And why require a non-const ref to something you can only copy?
bool AddTask(tjob const &job) {
_taskqueue.push(job);
return true;
}
is better. Similarly for the other templated methods.
i need to create queue of classes
No, you don't, and in fact you can't (I suppose you could create a queue of typeinfo_t if you really wanted). You need to create a queue of objects. Fortunately that's what you're actually doing, since calling an object reference PClass doesn't make it a pointer-to-class.
This might seem (and indeed be) pedantic, but it's generally easier for everyone if you get the terminology right.