I have to implement a simple "unique_ptr" class supporting only a constructor, destructor, –>, *, and release(). And I did below.
However, it feels weird to write "up.operator->()" to get the pointer p. I would be more logical to write "up->p". But how do I do that? Thanks!
#include <iostream>
#include <stdexcept>
template <class T>
class unique_ptr
{
T *p;
public:
unique_ptr(T *ptr)
: p{ptr}
{
}
~unique_ptr() { delete p; }
T *operator->() const { return p; } // returns a pointer
T operator*() const { return *p; }
T *release()
{
T *ptr = p;
p = nullptr;
return ptr;
}
};
template <class T>
void print(const unique_ptr<T> &up, const std::string &s)
{
std::cout << s << " up.operator->(): " << up.operator->() << '\n';
std::cout << s << " up.operator*(): " << up.operator*() << '\n';
}
int main()
try
{
int *ptr = new int(10);
unique_ptr<int> up(ptr);
print(up, "up: ");
}
catch (std::exception &e)
{
std::cerr << "exception: " << e.what() << '\n';
return 1;
}
catch (...)
{
std::cerr << "exception\n";
return 2;
}
However, it feels weird to write "up.operator->()" to get the pointer p.
It feels weird because the member access operator is not generally used to get a pointer to the object (although you can do it using the operator->() syntax, as you demonstrated). Member access operator is used to access members of the object. In your example, you have a unique pointer of int. int doesn't have a member, so it doesn't make sense to use the member access operator.
Here is an example of how to use it:
struct S {
int member;
};
unique_ptr<S> up(new S{10});
int value_of_member = up->member;
would be more logical to write "up->p"
That wouldn't be logical unless p is a member of the pointed object.
How to create an operator-> for a class unique_ptr
Like you did in the example. As far as I can tell, there was no problem with how you create the operator, but rather how to use it.
P.S. Your unique pointer is copyable, movable and assignable, but those operations are horribly broken leading to undefined behaviour. See rule of 5.
As others have noted in comments this implementation of a single ownership smart pointer is incomplete and the operator*() is incorrect in that it doesn't return a reference and thus does not facilitate making assignments through the pointer.
However to answer the question,
it feels weird to write "up.operator->()" to get the pointer p. I
would be more logical to write "up->p". But how do I do that?
Well you wouldnt want to do that as p is part of the private implementation of your smart pointer class. It is weird to write up.operator->() because that is not how the -> is typically used. It is typically used as shorthand to access the members of a struct or class that is slightly less verbose than the * operator in combination with member access via .. To use your pointer then in a less weird way you need the template parameter to be instantiated with some type that has fields, e.g.
struct foo {
int bar;
};
void print(const unique_ptr<foo>& up, const std::string& s)
{
std::cout << s << " up.operator->(): " << up->bar << '\n';
std::cout << s << " up.operator*(): " << (*up).bar << '\n';
}
int main()
{
unique_ptr<foo> up(new foo{ 42 });
print(up, "up: ");
}
I am trying to make a deep copy of the object but for some reason I keep getting an error thrown at me.
Invalid address specified to RtlValidateHeap( 000002081EF60000, 000002081EF755C0 )
What does this mean? I have commented out the last two lines as this is not what causes the error but is what I would like to achieve.
#include "pch.h"
#include <iostream>
class Constant
{
public:
int Value;
Constant(int value) {
Value = value;
}
void set_value(int new_value) {
Value = new_value;
}
int get_value() {
return Value;
}
};
int main() {
std::shared_ptr<Constant> foo = std::make_shared<Constant>(1);
std::shared_ptr<Constant> bar(foo.get());
//bar->set_value(4);
//std::cout << (foo->get_value()) << " should be differnt than " << (bar->get_value());
return 0;
}
I expect the output "1 should be different from 4".
You are getting heap corruption due to a double-free problem. Your second shared_ptr is constructed with a raw pointer, which is already managed by the first shared_ptr. So both try to manage the same object, which leads to a double-free at the end of the scope.
To make a copy of an object in C++, just use copy construction:
#include "pch.h"
#include <iostream>
class Constant
{
public:
int Value;
Constant(int value) {
Value = value;
}
void set_value(int new_value) {
Value = new_value;
}
int get_value() {
return Value;
}
};
int main() {
Constant foo(1);
Constant bar(foo); // copy-construction
bar.set_value(4);
std::cout << (foo.get_value()) << " should be differnt than " << (bar.get_value());
return 0;
}
Note: in this example it is sufficient to rely on the default compiler-generated copy constructor.
Phil1970 got it right in the comments.
#include "pch.h"
#include <iostream>
class Constant
{
public:
int Value;
Constant(int value) {
Value = value;
}
void set_value(int new_value) {
Value = new_value;
}
int get_value() {
return Value;
}
};
int main() {
std::shared_ptr<Constant> foo = std::make_shared<Constant>(1);
std::shared_ptr<Constant> bar = std::make_shared<Constant>(*foo);
bar->set_value(4);
std::cout << (foo->get_value()) << " should be differnt than " << (bar->get_value());
return 0;
}
His solution allows you to use shared pointers and still obtain the desired result. Thanks Phil!
When you call this function:
std::shared_ptr<Constant> bar(foo.get());
You are directly taking the data pointer of the ptr internal and adding an additional controller(bar) to it. So don't pass the data ptr instead of the share ptr itself to the constructor.It should be like:
std::shared_ptr<Constant> bar(foo);
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.
Consider the following setup.
Base class:
class Thing {
int f1;
int f2;
Thing(NO_INIT) {}
Thing(int n1 = 0, int n2 = 0): f1(n1),f2(n2) {}
virtual ~Thing() {}
virtual void doAction1() {}
virtual const char* type_name() { return "Thing"; }
}
And derived classes that are different only by implementation of methods above:
class Summator {
Summator(NO_INIT):Thing(NO_INIT) {}
virtual void doAction1() override { f1 += f2; }
virtual const char* type_name() override { return "Summator"; }
}
class Substractor {
Substractor(NO_INIT):Thing(NO_INIT) {}
virtual void doAction1() override { f1 -= f2; }
virtual const char* type_name() override { return "Substractor"; }
}
The task I have requires ability to change class (VTBL in this case) of existing objects on the fly. This is known as dynamic subclassing if I am not mistaken.
So I came up with the following function:
// marker used in inplace CTORs
struct NO_INIT {};
template <typename TO_T>
inline TO_T* turn_thing_to(Thing* p)
{
return ::new(p) TO_T(NO_INIT());
}
that does just that - it uses inplace new to construct one object in place of another. Effectively this just changes vtbl pointer in objects. So this code works as expected:
Thing* thing = new Thing();
cout << thing->type_name() << endl; // "Thing"
turn_thing_to<Summator>(thing);
cout << thing->type_name() << endl; // "Summator"
turn_thing_to<Substractor>(thing);
cout << thing->type_name() << endl; // "Substractor"
The only major problems I have with this approach is that
a) each derived classes shall have special constructors like Thing(NO_INIT) {} that shall do precisely nothing. And b) if I will want to add members like std::string to the Thing they will not work - only types that have NO_INIT constructors by themselves are allowed as members of the Thing.
Question: is there a better solution for such dynamic subclassing that solves 'a' and 'b' problems ? I have a feeling that std::move semantic may help to solve 'b' somehow but not sure.
Here is the ideone of the code.
(Already answered at RSDN http://rsdn.ru/forum/cpp/5437990.1)
There is a tricky way:
struct Base
{
int x, y, z;
Base(int i) : x(i), y(i+i), z(i*i) {}
virtual void whoami() { printf("%p base %d %d %d\n", this, x, y, z); }
};
struct Derived : Base
{
Derived(Base&& b) : Base(b) {}
virtual void whoami() { printf("%p derived %d %d %d\n", this, x, y, z); }
};
int main()
{
Base b(3);
Base* p = &b;
b.whoami();
p->whoami();
assert(sizeof(Base)==sizeof(Derived));
Base t(std::move(b));
Derived* d = new(&b)Derived(std::move(t));
printf("-----\n");
b.whoami(); // the compiler still believes it is Base, and calls Base::whoami
p->whoami(); // here it calls virtual function, that is, Derived::whoami
d->whoami();
};
Of course, it's UB.
For your code, I'm not 100% sure it's valid according to the standard.
I think the usage of the placement new which doesn't initialize any member variables, so to preserve previous class state, is undefined behavior in C++. Imagine there is a debug placement new which will initialize all uninitialized member variable into 0xCC.
union is a better solution in this case. However, it does seem that you are implementing the strategy pattern. If so, please use the strategy pattern, which will make code a lot easier to understand & maintain.
Note: the virtual should be removed when using union.
Adding it is ill-formed as mentioned by Mehrdad, because introducing virtual function doesn't meet standard layout.
example
#include <iostream>
#include <string>
using namespace std;
class Thing {
int a;
public:
Thing(int v = 0): a (v) {}
const char * type_name(){ return "Thing"; }
int value() { return a; }
};
class OtherThing : public Thing {
public:
OtherThing(int v): Thing(v) {}
const char * type_name() { return "Other Thing"; }
};
union Something {
Something(int v) : t(v) {}
Thing t;
OtherThing ot;
};
int main() {
Something sth{42};
std::cout << sth.t.type_name() << "\n";
std::cout << sth.t.value() << "\n";
std::cout << sth.ot.type_name() << "\n";
std::cout << sth.ot.value() << "\n";
return 0;
}
As mentioned in the standard:
In a union, at most one of the non-static data members can be active at any time, that is, the value of at most one of the non-static data members can be stored in a union at any time. [ Note: One special guarantee is made in order to simplify the use of unions: If a standard-layout union contains several standard-layout structs that share a common initial sequence (9.2), and if an object of this standard-layout union type contains one of the standard-layout structs, it is permitted to inspect the common initial sequence of any of standard-layout struct members; see 9.2. — end note ]
Question: is there a better solution for such dynamic subclassing that solves 'a' and 'b' problems ?
If you have fixed set of sub-classes then you may consider using algebraic data type like boost::variant. Store shared data separately and place all varying parts into variant.
Properties of this approach:
naturally works with fixed set of "sub-classes". (though, some kind of type-erased class can be placed into variant and set would become open)
dispatch is done via switch on small integral tag. Sizeof tag can be minimized to one char. If your "sub-classes" are empty - then there will be small additional overhead (depends on alignment), because boost::variant does not perform empty-base-optimization.
"Sub-classes" can have arbitrary internal data. Such data from different "sub-classes" will be placed in one aligned_storage.
You can make bunch of operations with "sub-class" using only one dispatch per batch, while in general case with virtual or indirect calls dispatch will be per-call. Also, calling method from inside "sub-class" will not have indirection, while with virtual calls you should play with final keyword to try to achieve this.
self to base shared data should be passed explicitly.
Ok, here is proof-of-concept:
struct ThingData
{
int f1;
int f2;
};
struct Summator
{
void doAction1(ThingData &self) { self.f1 += self.f2; }
const char* type_name() { return "Summator"; }
};
struct Substractor
{
void doAction1(ThingData &self) { self.f1 -= self.f2; }
const char* type_name() { return "Substractor"; }
};
using Thing = SubVariant<ThingData, Summator, Substractor>;
int main()
{
auto test = [](auto &self, auto &sub)
{
sub.doAction1(self);
cout << sub.type_name() << " " << self.f1 << " " << self.f2 << endl;
};
Thing x = {{5, 7}, Summator{}};
apply(test, x);
x.sub = Substractor{};
apply(test, x);
cout << "size: " << sizeof(x.sub) << endl;
}
Output is:
Summator 12 7
Substractor 5 7
size: 2
LIVE DEMO on Coliru
Full Code (it uses some C++14 features, but can be mechanically converted into C++11):
#define BOOST_VARIANT_MINIMIZE_SIZE
#include <boost/variant.hpp>
#include <type_traits>
#include <functional>
#include <iostream>
#include <utility>
using namespace std;
/****************************************************************/
// Boost.Variant requires result_type:
template<typename T, typename F>
struct ResultType
{
mutable F f;
using result_type = T;
template<typename ...Args> T operator()(Args&& ...args) const
{
return f(forward<Args>(args)...);
}
};
template<typename T, typename F>
auto make_result_type(F &&f)
{
return ResultType<T, typename decay<F>::type>{forward<F>(f)};
}
/****************************************************************/
// Proof-of-Concept
template<typename Base, typename ...Ts>
struct SubVariant
{
Base shared_data;
boost::variant<Ts...> sub;
template<typename Visitor>
friend auto apply(Visitor visitor, SubVariant &operand)
{
using result_type = typename common_type
<
decltype( visitor(shared_data, declval<Ts&>()) )...
>::type;
return boost::apply_visitor(make_result_type<result_type>([&](auto &x)
{
return visitor(operand.shared_data, x);
}), operand.sub);
}
};
/****************************************************************/
// Demo:
struct ThingData
{
int f1;
int f2;
};
struct Summator
{
void doAction1(ThingData &self) { self.f1 += self.f2; }
const char* type_name() { return "Summator"; }
};
struct Substractor
{
void doAction1(ThingData &self) { self.f1 -= self.f2; }
const char* type_name() { return "Substractor"; }
};
using Thing = SubVariant<ThingData, Summator, Substractor>;
int main()
{
auto test = [](auto &self, auto &sub)
{
sub.doAction1(self);
cout << sub.type_name() << " " << self.f1 << " " << self.f2 << endl;
};
Thing x = {{5, 7}, Summator{}};
apply(test, x);
x.sub = Substractor{};
apply(test, x);
cout << "size: " << sizeof(x.sub) << endl;
}
use return new(p) static_cast<TO_T&&>(*p);
Here is a good resource regarding move semantics: What are move semantics?
You simply can't legally "change" the class of an object in C++.
However if you mention why you need this, we might be able to suggest alternatives. I can think of these:
Do v-tables "manually". In other words, each object of a given class should have a pointer to a table of function pointers that describes the behavior of the class. To modify the behavior of this class of objects, you modify the function pointers. Pretty painful, but that's the whole point of v-tables: to abstract this away from you.
Use discriminated unions (variant, etc.) to nest objects of potentially different types inside the same kind of object. I'm not sure if this is the right approach for you though.
Do something implementation-specific. You can probably find the v-table formats online for whatever implementation you're using, but you're stepping into the realm of undefined behavior here so you're playing with fire. And it most likely won't work on another compiler.
You should be able to reuse data by separating it from your Thing class. Something like this:
template <class TData, class TBehaviourBase>
class StateStorageable {
struct StateStorage {
typedef typename std::aligned_storage<sizeof(TData), alignof(TData)>::type DataStorage;
DataStorage data_storage;
typedef typename std::aligned_storage<sizeof(TBehaviourBase), alignof(TBehaviourBase)>::type BehaviourStorage;
BehaviourStorage behaviour_storage;
static constexpr TData *data(TBehaviourBase * behaviour) {
return reinterpret_cast<TData *>(
reinterpret_cast<char *>(behaviour) -
(offsetof(StateStorage, behaviour_storage) -
offsetof(StateStorage, data_storage)));
}
};
public:
template <class ...Args>
static TBehaviourBase * create(Args&&... args) {
auto storage = ::new StateStorage;
::new(&storage->data_storage) TData(std::forward<Args>(args)...);
return ::new(&storage->behaviour_storage) TBehaviourBase;
}
static void destroy(TBehaviourBase * behaviour) {
auto storage = reinterpret_cast<StateStorage *>(
reinterpret_cast<char *>(behaviour) -
offsetof(StateStorage, behaviour_storage));
::delete storage;
}
protected:
StateStorageable() = default;
inline TData *data() {
return StateStorage::data(static_cast<TBehaviourBase *>(this));
}
};
struct Data {
int a;
};
class Thing : public StateStorageable<Data, Thing> {
public:
virtual const char * type_name(){ return "Thing"; }
virtual int value() { return data()->a; }
};
Data is guaranteed to be leaved intact when you change Thing to other type and offsets should be calculated at compile-time so performance shouldn't be affected.
With a propert set of static_assert's you should be able to ensure that all offsets are correct and there is enough storage for holding your types. Now you only need to change the way you create and destroy your Things.
int main() {
Thing * thing = Thing::create(Data{42});
std::cout << thing->type_name() << "\n";
std::cout << thing->value() << "\n";
turn_thing_to<OtherThing>(thing);
std::cout << thing->type_name() << "\n";
std::cout << thing->value() << "\n";
Thing::destroy(thing);
return 0;
}
There is still UB because of not reassigning thing which can be fixed by using result of turn_thing_to
int main() {
...
thing = turn_thing_to<OtherThing>(thing);
...
}
Here is one more solution
While it slightly less optimal (uses intermediate storage and CPU cycles to invoke moving ctors) it does not change semantic of original task.
#include <iostream>
#include <string>
#include <memory>
using namespace std;
struct A
{
int x;
std::string y;
A(int x, std::string y) : x(x), y(y) {}
A(A&& a) : x(std::move(a.x)), y(std::move(a.y)) {}
virtual const char* who() const { return "A"; }
void show() const { std::cout << (void const*)this << " " << who() << " " << x << " [" << y << "]" << std::endl; }
};
struct B : A
{
virtual const char* who() const { return "B"; }
B(A&& a) : A(std::move(a)) {}
};
template<class TO_T>
inline TO_T* turn_A_to(A* a) {
A temp(std::move(*a));
a->~A();
return new(a) B(std::move(temp));
}
int main()
{
A* pa = new A(123, "text");
pa->show(); // 0xbfbefa58 A 123 [text]
turn_A_to<B>(pa);
pa->show(); // 0xbfbefa58 B 123 [text]
}
and its ideone.
The solution is derived from idea expressed by Nickolay Merkin below.
But he suspect UB somewhere in turn_A_to<>().
I have the same problem, and while I'm not using it, one solution I thought of is to have a single class and make the methods switches based on a "item type" number in the class. Changing type is as easy as changing the type number.
class OneClass {
int iType;
const char* Wears() {
switch ( iType ) {
case ClarkKent:
return "glasses";
case Superman:
return "cape";
}
}
}
:
:
OneClass person;
person.iType = ClarkKent;
printf( "now wearing %s\n", person.Wears() );
person.iType = Superman;
printf( "now wearing %s\n", person.Wears() );
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.