I'm trying to figure out how to create a binary tree class in Managed C++ for a school project. I've found really good examples in unmanaged C++ and some in C#, so I have been able to get a fairly good understanding ow what's going on, but I just can't seem to figure it out in Managed C++. What I'd like to find out is: why am I getting the stack overflow (see below), and is this a wise approach? Here's my class:
#pragma once
#include "stdafx.h"
#include <iostream>
#include <deque>
#include <climits>
using namespace std;
using namespace System;
using namespace System::Collections;
ref struct Node
{
int data;
Node ^parent;
Node ^left;
Node ^right;
// constructors
// default constructor
Node (){}
// constructor that takes a node with no leafs
// a constructor that accepts a new node with no children
Node(int input)
{
Node ^node = gcnew Node(input);
node->data =input;
node->left = nullptr;
node->right = nullptr;
node->parent = nullptr;
}
// method to create a new Node
Node ^newNode(int data)
{
Node ^node = gcnew Node;
node->data = data;
node->left = nullptr;
node->right = nullptr;
node->parent = nullptr;
return node;
}
// method that inserts a new node into an existing tree
Node ^insertNode(Node ^node, int input)
{
Node ^p;
Node ^returnNode;
if (node == nullptr)
{
returnNode = newNode(input);
returnNode->parent = p;
return returnNode;
}
if (input <= node->data)
{
p = node;
node->left = insertNode(node->left, input);
}
else
{
p = node;
node->right = insertNode(node->right, input);
}
return node;
}
};
And when I create a new instance, and try to add a node, I get a stack overflow exception.
#include "stdafx.h"
#include "GenericNodeClass.h"
#include "BinarySearchTreeClass.h"
using namespace std;
using namespace System;
int main ()
{
BinarySearchTreeClass^ BTree = gcnew BinarySearchTreeClass();
Node ^newNode = gcnew Node(7);
newNode = newNode->insertNode(newNode, 6); // this just looks stupid
return 0;
}
In your Node constructor...
Node(int input)
{
...you unconditionally call the Node constructor...
Node ^node = gcnew Node(input);
That can't end well. Why are you constructing a new Node in the Node constructor? When the Node constructor is called, it is called to construct the *this object--instead of creating a new Node, you should initialize the current instance.
Likewise in your insertNode member function--it already has access to the *this object; there's no need to pass it via a separate parameter.
Related
Am trying to pass data structure to QT thread and but no success.
here is what am doing and have done.
i prepare data for the thread, like this and then tried to pass prepared data to thread before starting.
void mytable::prepare_data(){
// get table row count
int rowCount = ui->my_table_view->rowCount();
// create structure array based on rowCount
pnp_com_info pnp_data[rowCount];
/* pnp_com_info structure defined it top of file below includes to make it global
struct pnp_com_info{
QString com_name = "";
int x = 0;
int y = 0;
int angle = 0;
bool status = false;
};
*/
// loop on table rows columns and load pnp_data with data of columns
// PROBLEM : how to pass pnp_data structure to thread side ?
// can pass basic vars like
RunJobThread->mynum = 10;
// start QT thread
RunJobThread->start();
// std:: thread experiment
// std::stdthreadtest(pnp_data,rowCount);
}
run_job_thread.h source code
#ifndef RUN_JOB_THREAD_H
#define RUN_JOB_THREAD_H
#include <QObject>
#include <QThread>
class run_job_thread : public QThread
{
Q_OBJECT
public:
run_job_thread();
void run();
int mynum;
struct pnp_com_info_thread{
QString com_name = "";
int x = 0;
int y = 0;
int angle = 0;
bool status = false;
};
bool Stop; // bool to stop the job
signals:
void select_row_of_table_signal(int);
public slots:
};
#endif // RUN_JOB_THREAD_H
run_job_thread.cpp source code
#include "run_job_thread.h"
#include <QtCore>
run_job_thread::run_job_thread()
{
}
// run the thread
void run_job_thread::run(){
qDebug() << "my num passed value is : "<<this->mynum; // output : 10
// Goal : loop on pnp_data structure and emit signal to table rows
emit select_row_of_table_signal(5);
}
things i tried
instead of struct i tried to use other data containers like map, multimap, vectors but they give error , as am initializing pnp_com_info struct inside mytable::prepare_data() function based on rowCount which make it local and limited to prepare_data() function but with map,multimap,vector my plan was that they will be global and i will be able to access it from thread, however it not worked.
std::map<std::string, int,int,int> pnp_com_info; // error: too many template arguments for class template 'map'
std::multimap<std::string, int,int,int,bool> pnp_com_info; // error: too many template arguments for class template 'multimap'
std::vector<std::string, int,int,int,bool> pnp_com_info; // error: too many template arguments for class template 'vector'
i also tried std::thread which was partial success , i mean it was working ok but looks like std::thread not works with QT GUI thread as upon running app GUI will go freez although std::thread was doing its job
I would suggest to do the following, because the declaration of the
pnp_com_info pnp_data[rowCount];
is inside a context i think their lifecycle will be lost once you leave it, other problem is that it would be really "unsafe" to create this kind of arrays and then pass it from one side to another. Therefore I would create a QList and then pass either a copy or the reference to the worker thread. So
1) Create a QList pnp_data, in the public part of mytable
2) Fill all data using a for loop as follows.
3) Create another QList pnp_data or a QList *pnp_data (if you want to use a copy or a pointer)
4) Then just pass either a copy or a reference to the worker thread.
Then it should look like this:
mytable.h source code
public: QList<pnp_com_info> pnp_data;
mytable.cpp source code
void mytable::prepare_data(){
// get table row count
int rowCount = ui->my_table_view->rowCount();
// HERE YOU LOAD ALL THE VALUES TO THE LIST
for(int i = 0; i<rowCount; i++){
pnp_com_info itemToInsert;
//FILL HERE THE itemToInsert
//Insert the item inside the list.
pnp_data.append(itemToInsert);
}
// PROBLEM : how to pass pnp_data structure to thread side ?
// Either pass it as a copy
RunJobThread->pnp_data = pnp_data;
//or as a reference
QList<pnp_com_info> *pnpDataPointer = &pnp_data;
RunJobThread->pnp_data_reference = pnpDataPointer;
// start QT thread
RunJobThread->start();
// std:: thread experiment
// std::stdthreadtest(pnp_data,rowCount);
}
run_job_thread.h source code
#ifndef RUN_JOB_THREAD_H
#define RUN_JOB_THREAD_H
#include <QObject>
#include <QThread>
class run_job_thread : public QThread
{
Q_OBJECT
public:
run_job_thread();
void run();
struct pnp_com_info_thread{
QString com_name = "";
int x = 0;
int y = 0;
int angle = 0;
bool status = false;
};
QList<pnp_com_info> pnp_data; //This one if you create a copy
QList<pnp_com_info> *pnp_data_reference; //This if you want a pointer
bool Stop; // bool to stop the job
signals:
void select_row_of_table_signal(int);
public slots:
};
#endif // RUN_JOB_THREAD_H
I hope this helps.
First, don't subclass QThread to create a worker - re-read How To Really, Truly Use QThreads; The Full Explanation by Maya Posch. You will find it much more manageable to create a worker object and connect the threads started() to your worker's main method, and the worker's signals to the thread's quit() and deleteLater().
Then, it should be much more straightforward to pass your data to the worker before it's moved to the thread, or to use a signal connection if it needs to be passed when the worker is running (remember to register your structure with the meta-object system for that).
I am using Rcpp to create a package in R that leverages C++ code. I have read all of the Rcpp vignettes, but I haven't been able to find a solution to the following problem.
One of the C++ classes I'm trying to use contains a pointer. I am exposing the class using a module. When I try to install the package in R, I get the following error.
error: expected unqualified-id before '*' token.field("*w", &ffm_model::*w)
What am I doing wrong?
Code for Class Containing Pointer
typedef float ffm_float;
typedef int ffm_int;
class ffm_model {
public:
ffm_int n; // number of features
ffm_int m; // number of fields
ffm_int k; // number of latent factors
ffm_float *w = nullptr;
bool normalization;
~ffm_model();
};
Code for Corresponding RCPP Module
RCPP_MODULE(ffmModelMod){
using namespace Rcpp;
//Expose class as ffm_model on the r side
class_<ffm_model>( "ffm_model")
.field("n", &ffm_model::n)
.field("m", &ffm_model::m)
.field("k", &ffm_model::k)
.field("*w", &ffm_model::*w)
.field("normalization", &ffm_model::normalization)
.method("~ffm_model",&ffm_model::~ffm_model)
;
}
I had a similar problem, and as Dirk mentions, it is due to types that cannot be mapped automatically, such as float*.
The following workaround works for me:
Do not expose the fields with problematic types to R.
Instead, expose get() and set() functions to the fields above.
Here is an example, in which both the (unproblematic) value field and the (problematic) child field (a pointer to an object of the same class) are hidden:
Class
#include <Rcpp.h>
using namespace Rcpp;
class node
{
public:
double value; // Voluntarily hidden from R
node* child; // Must be hidden from R
// Exposed functions
void setVal(double value);
double getVal();
node* createNode(double value); // return pointer to a node
node* createChild(double value); // set child
node* getChild();
};
Methods
void node::setVal(double value){
this->value = value;
}
double node::getVal(){
return this->value;
}
node* node::createNode(double value){
node* n = new node;
n->value = value;
return n;
}
node* node::createChild(double value){
this->child = createNode(value);
return child;
}
node* node::getChild(){
return this->child;
}
RCPP Module
RCPP_MODULE(gbtree_module){
using namespace Rcpp;
class_<node>("node")
.constructor()
.method("setVal", &node::setVal)
.method("getVal", &node::getVal)
.method("createNode", &node::createNode)
.method("createChild", &node::createChild)
.method("getChild", &node::getChild)
;
}
Usage in R
n <- new(node)
n$setVal(2)
n$getVal()
n2 <- n$createNode(1) # unrelated node
n3 <- n$createChild(3) #child node
n$getChild() #pointer to child node
n3
#include <iostream>
#include <mutex>
using namespace std;
class A;
class B {
public:
B(A *_parent = nullptr) {
parent = _parent;
}
A *parent;
};
class A {
public:
std::mutex m;
B *b;
A() {
b = new B(this);
}
};
int main() {
A a_obj;
B *b = new B(&a_obj);
//b->parent->m.lock();
return 0;
}
I believe the composed objects above function as expected and I've been using a similar design (my A creates B's and adds them to a data structure. The B's are constructed with references to their parent.)
When I tried to add threadsafe message-passing between A's and B's, the program crashed whenever a B tried to use a threadsafe container in A.
The code above recreates the problem. Why can B not acquire A's mutex?
I have these three.h files that are giving me so many mind-boggling errors, that there must be some fundamental issue that I'm overlooking. My objective is to create an efficient linked list. I realize that there are some logic issues, but right now, I'm more interested in getting it to compile.
Basic Node class:
#pragma once
#include "stdafx.h"
#include <iostream>
#include <deque>
#include <climits>
#include "FreeList.h"
using namespace std;
using namespace System;
using namespace System::Collections;
using namespace System::Collections::Generic;
namespace ListTestProgram
{
generic <typename E> ref class LinkNode
{
private:
LinkNode<E>^ ptr;
FreeList<E>^ freelist;
public:
E element;
LinkNode^ next;
// constructors
LinkNode( E elemval, LinkNode<E>^ nextval = nullptr)
{
element = elemval; next = nextval;
freelist = gcnew FreeList<E>;
}
LinkNode(LinkNode<E>^ nextval = nullptr)
{
next = nextval;
freelist = gcnew FreeList<E>;
}
LinkNode<E>^ newNode()
{
freelist->nextNode();
}
void deleteNode(LinkNode<E>^ ptr)
{
freelist->add((LinkNode<E>^)ptr)->next;
}
};
}
Link class:
// LinkList.h provides for implementation of a linked list
#pragma once
#include "stdafx.h"
#include "LinkNode.h"
#include <iostream>
#include <deque>
#include <climits>
using namespace std;
using namespace System;
using namespace System::Collections;
using namespace System::Collections::Generic;
namespace ListTestProgram
{
generic <typename E> ref class LinkList
{
private:
LinkNode<E>^ head; // pointer to list header
LinkNode<E>^ tail; // pointer to last element
LinkNode<E>^ curr; //access to current element
int cnt; // size of list
static int defaultSize = 100;
void init() // Initializer
{
curr = tail = head = gcnew LinkNode<E>();
cnt = 0;
}
void removal() // Return link nodes to free store
{
while (head != nullptr)
{
curr = head;
head = head->next;
delete curr;
}
}
public:
LinkList<E>(){}
LinkList<E>(int size=defaultSize) {init(); } // Constructor
~LinkList() { removal(); } // Destructor
void print(); // print list contents
void clear() { removal(); init(); } // Clear list
// Insert "it" at current position
void insert (E it)
{
curr->next = gcnew LinkNode<E>(it, curr->next);
if(tail == curr) tail = curr->next; // new tail
cnt++;
}
void append(E it)
{
tail = tail->next = gcnew LinkNode<E> (it, nullptr);
cnt++;
}
// Remove and return current element
E remove()
{
assert(curr->next != nullptr, "No element");
E it = curr->next->element; // Remember value
LinkNode<E>^ ltemp = curr->next; // Rember link node
if(tail == curr->next) tail = curr; // reset tail
curr->next = curr->next->next; // remove from list
delete ltemp;
cnt--;
return it;
}
void moveToNext() // Place curr to head of list
{
curr = head;
}
void moveToEnd() // Place curr at end of list
{
curr = tail;
}
// Move curr one step left; no change if already at front
void prev()
{
if (curr == head) return;
LinkNode<E>^ temp = head;
// March down the list until we find the previous element
while (temp->next!=curr) temp= temp->next;
curr = temp;
}
// Move curr one step right; no change if already at end
void next()
{
if (curr != tail) curr = curr->next;
}
// Return the position of the current element
int currPos()
{
LinkNode<E>^ temp = head;
int i;
for (i = 0; curr != temp; i++)
temp = temp->next;
return i;
}
// Move down list to "pos" position
void moveToPos(int pos)
{
assert((pos>=0)&&(pos<=cnt), "Position out of range.");
curr = head;
for (int i=0; i<pos; i++) curr = curr->next;
}
E getValue()
{
assert(curr->next != nullptr, "No value");
return curr->next->element;
}
};
}
And the FreeList class, which I want to hold nodes that are deleted from the linked list so that they can be reused, avoiding repeated calls to delete and new.
// FreeList.h provides a stack of nodes from which new nodes from the LinkNode class can be
// derived. This is to limit the number of calls to gcnew, to minimize proceccor time. Items in the
// FreeList stack are returned to LinkNode calls when a new node is called for.
#pragma once
#include "stdafx.h"
#include <iostream>
#include <deque>
#include <climits>
#include "LinkNode.h"
using namespace std;
using namespace System;
using namespace System::Collections;
using namespace System::Collections::Generic;
namespace ListTestProgram
{
generic <typename E> ref class FreeList
{
/**** members ****/
public: Stack^ freelist;
/**** constructors / Destructors ****/
FreeList() { freelist = gcnew Stack; }
~FreeList(){}
/**** methods ****/
// return an instance of LinkNode
LinkNode<E>^ nextNode ()
{
if (freelist->Count != 0)
return freelist->Pop();
else
{
repopulateStack();
nextNode(node);
}
}
// repopulate an empty stack
void repopulateStack()
{
for (int i = 0; i < 100; i++)
freelist->Push(gcnew LinkNode<E>());
}
// add a deleted node to the freelist for later use
void add(LinkNode<E>^ trash)
{
freelist->Push(trash);
}
};
}
A few of my errors are:
Error 13 error C2039: 'nextNode' : is not a member of 'ListTestProgram::FreeList<E>' c:\users\ed\documents\visual studio 2012\school_projects\cpp programs\cpp_advanced\testinglists\testinglists\LinkNode.h 43 1 TestingLists
Error 6 error C2061: syntax error : identifier 'LinkNode' c:\users\ed\documents\visual studio 2012\school_projects\cpp programs\cpp_advanced\testinglists\testinglists\FreeList.h 52 1 TestingLists
Error 10 error C2065: 'trash' : undeclared identifier c:\users\ed\documents\visual studio 2012\school_projects\cpp programs\cpp_advanced\testinglists\testinglists\FreeList.h 54 1 TestingLists
Error 3 error C2143: syntax error : missing ';' before '<' c:\users\ed\documents\visual studio 2012\school_projects\cpp programs\cpp_advanced\testinglists\testinglists\FreeList.h 33 1 TestingLists
Error 1 error C2872: 'Stack' : ambiguous symbol c:\users\ed\documents\visual studio 2012\school_projects\cpp programs\cpp_advanced\testinglists\testinglists\FreeList.h 23 1 TestingLists
Error 6 error C2061: syntax error : identifier 'LinkNode' c:\users\ed\documents\visual studio 2012\school_projects\cpp programs\cpp_advanced\testinglists\testinglists\FreeList.h 52 1 TestingLists
Your headers have circular dependencies: FreeList.h depends on LinkNode.h which depends on FreeList.h. Header file dependencies must form a directed, acyclic graph.
I am getting multiple, confusing errors when building this school assignment and am hoping for some direction on what might be the problem. I wouldn't normally write it like this, but I put everything into one file as I try to debug this. Using Visual Studios Express 2012. I'm getting over 30 errors when I build, so I'm sure there is something fundamental that I am simply overlooking. Just a suggestion please, not looking for anyone to do my homework. Thanks
#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include "MessageDisplayClass.h"
#include "LogMessageClass.h"
#include "TimerEventArgs.h"
using namespace System;
ref class CustomTimerClass
{
private:
static bool stopFlag = false;
// create instance of TimerEventArgs
TimerEventArgs^ timerEvent;
public:
CustomTimerClass(void)
{
}
delegate void CustomTimerClass::TimerAlarmHandler(/*Object^ sender, TimerEventArgs^ args*/);
event CustomTimerClass::TimerAlarmHandler^ OnTimerAlarm;
property bool StopFlag
{
bool get(void)
{
return stopFlag;
}
void set(bool b)
{
stopFlag = b;
}
}
void run()
{
Sleep(1000);
raiseTimerAlarm();
}
void OnStart()
{
// create instances of DisplayMessageClass and LogMessageClass classes
DisplayMessageClass^ messageDisplayer = gcnew DisplayMessageClass(this);
LogMessageClass^ messageLogger = gcnew LogMessageClass(this);
// display and log messages concerning this event
messageDisplayer->displayMessage(this, timerEvent);
messageLogger->logMessage(this, timerEvent);
}
void raiseTimerAlarm()
{
// create instance of TimerEventArgs and get time of instance creation
timerEvent = gcnew TimerEventArgs();
String^ eventTime = timerEvent->EventTime;
// tie this instance of CustomTimerClass to OnTimerAlarm event and start event
this->OnTimerAlarm += gcnew TimerAlarmHandler(this, &CustomTimerClass::OnStart);
OnTimerAlarm();
}
};
ref class MainProgram
{
int main(array<System::String ^> ^args)
{
CustomTimerClass^ timerClass = gcnew CustomTimerClass();
DisplayMessageClass^ messageClass = gcnew DisplayMessageClass();
LogMessageClass^ logerClass = gcnew LogMessageClass();
timerClass->run();
return 0;
}
};
At the point you're trying to use the various classes, the compiler doesn't know about them yet. Move your main() function to the end of the file. Or better, split your class definitions in their own header files and then include them in your main source file.
There are other related problems too. For example, you're trying to use the TimerEventArgs class before the compiler knows about it. So you need to move the class definition up. This is why it's best to have each class in its own header file, and then include it where needed. Though it's not strictly unnecessary, if you declare/define everything in the correct order.
Other than wrong order of declarations, it looks like the problem is that the compiler doesn't recognize the ^ bit, which suggests you're not compiling as C++/CLI. Righ-click the project in Solution Explorer and go to Configuration Properties -> General, and make sure that Common Language Runtime Support is set to Common Language Runtime Support (/clr).
For the benefit of anyone else (other newbies): As it turns out, my suspicion that the problem lay in the fact that some of the classes were "#including" each other was the problem. Using forward declarations, combined with having to create a separate class altogether to act as a variable storage handler was the solution to my problem.
Here are the two classes that were giving me the biggest problem, corrected to function correctly:
/*
CustomTimerClass.h
*/
#include "StdAfx.h"
#include "LogMessageClass.h"
#include "MessageDisplayClass.h"
#include "TimerEventArgs.h"
#include "Variables.h"
//ref class MessageDisplayClass;
//ref class Variables;
using namespace System;
ref class CustomTimerClass
{
private:
static bool stopFlag = false;
// create instance of TimerEventArgs
TimerEventArgs^ timerEvent;
// create instance of MessageDisplayClass and LogMessageClass
MessageDisplayClass^ messageDisplayer;
LogMessageClass^ messageLogger;
Variables^ flagVariable;
public:
CustomTimerClass(void)
{
}
delegate void CustomTimerClass::TimerAlarmHandler();
event CustomTimerClass::TimerAlarmHandler^ OnTimerAlarm;
property bool StopFlag
{
bool get(void)
{
return stopFlag;
}
void set(bool b)
{
stopFlag = flagVariable->Flag;
}
}
void run()
{
Sleep(1000);
raiseTimerAlarm();
}
void OnStart()
{
// create instances of DisplayMessageClass and LogMessageClass classes
messageDisplayer = gcnew MessageDisplayClass(this, flagVariable);
messageLogger = gcnew LogMessageClass(this);
// display and log messages concerning this event
messageDisplayer->displayMessage(this, timerEvent);
messageLogger->logMessage(this, timerEvent);
}
void raiseTimerAlarm()
{
// create instance of TimerEventArgs and get time of instance creation
timerEvent = gcnew TimerEventArgs();
String^ eventTime = timerEvent->EventTime;
// tie this instance of CustomTimerClass to OnTimerAlarm event and start event
this->OnTimerAlarm += gcnew TimerAlarmHandler(this, &CustomTimerClass::OnStart);
OnTimerAlarm();
}
};
/*
MessageDisplayClass serves to display a message that
represents the time at which the TimerEventArgs class is
instantiated. This time is returned through a function
of TimerEventArgs class.
*/
#pragma once
#include "stdafx.h"
#include <iostream>
#include "TimerEventArgs.h"
#include "Variables.h"
using namespace System;
ref class CustomTimerClass; // FORWARD DECLARATION HERE CAN
// ONLY BE USED FOR REFERENCE. CANNOT
// BE USED WHEN METHODS OF THE CLASS
// ARE CALLED
ref class MessageDisplayClass
{
private:
CustomTimerClass^ customTimerRef;
// Variables CLASS CREATED SOLELY TO ACT AS GO-BETWEEN BETWEEN
// MessageDisplayClass and CustomTimerClass
Variables^ variableRef;
static int counter;
public:
// constructor
MessageDisplayClass(CustomTimerClass^ CustomTimerClassInput, Variables^ variableReference)
{
customTimerRef = CustomTimerClassInput;
variableRef = gcnew Variables (CustomTimerClassInput);
}
void displayMessage(Object^ sender, TimerEventArgs^ timer)
{
counter ++;
if (counter > 0)
{
variableRef->Flag = true;
Console::WriteLine("Message: an event occured at time stamp: " + timer->EventTime);
}
}
};