I'm trying to transfer a command line code that I have to a more visual program with a
GUI to enable easier use. The original code was in C++, so I'm using Visual C++ that is
available in Visual Studio Express 2012, but I have problems understanding the "new"
managed C++/CLI way of handling objects. Being new to CLI and managed C++, I was wondering
if someone can explain what I am doing wrong, and why it doesn't work. Now here is a
description of the code and the problem.
The program is essentially an optimization program:
There are multiple boxes (modes) in a system, each mode, depending on its type has a
few numerical coefficients that control its behavior and the way it responds to outside
excitation.
The program asks the user to specify the number of boxes and the type of each box.
Then tries to find the numerical coefficients that minimize the difference between
the system response with those obtained experimentally.
So, the UI has means for user to open the experimental result files, specify the number
of modes, and specify the type of each mode. Then, the user can initiate the processing
function by clicking on a start button, that initiates a background worker.
Following the example given in MSDN, I created a class that performs the work:
ref class curveFit
{
public: ref class CurrentState{
public:
int percentage;
int iterationNo;
int stage;
bool done;
multimode systemModel;
};
public:
int modes;
int returncode;
array<double> ^expExcitations;
array<double> ^expResults;
multimode systemModel;
private:
void fcn(int, int, double*, double*, int*);
double totalError(std::vector<double> &);
public:
delegate void fcndelegate(int, int, double*, double*, int*);
public:
curveFit(void);
curveFit^ fit(System::ComponentModel::BackgroundWorker^, System::ComponentModel::DoWorkEventArgs^, Options^);
};
multimode is just a container class: a list of different boxes.
ref class multimode
{
private:
Collections::Generic::List<genericBoxModel ^>^ models;
int modes;
public:
multimode(void);
multimode(const multimode%);
int modeNo(void);
void Add(genericBoxModel^);
void Clear();
genericBoxModel^ operator[](int);
multimode% operator=(const multimode%);
double result(double);
bool isValid();
std::vector<double> MapData();
void MapData(std::vector<double> &);
};
multimode::multimode(void)
{
models = gcnew Collections::Generic::List<genericBoxModel ^>();
modes = 0;
}
multimode::multimode(const multimode% rhs)
{
models = gcnew Collections::Generic::List<genericBoxModel ^>();
for(int ind = 0; ind < rhs.modes; ind++)
models->Add(rhs.models[ind]);
modes = rhs.modes;
}
int multimode::modeNo(void)
{
return modes;
}
void multimode::Add(genericBoxModel^ model)
{
models->Add(model);
modes++;
}
void multimode::Clear()
{
models->Clear();
modes = 0;
}
genericBoxModel^ multimode::operator[](int ind)
{
return models[ind];
}
multimode% multimode::operator=(const multimode% rhs)
{
models->Clear();
for(int ind = 0; ind < rhs.modes; ind++)
models->Add(rhs.models[ind]);
modes = rhs.modes;
return *this;
}
double multimode::result(double excitation)
{
double temp = 0.0;
for(int ind = 0; ind < modes; ind++)
temp += models[ind]->result(excitation);
return temp;
}
bool multimode::isValid()
{
bool isvalid = true;
if(modes < 1)
return false;
for(int ind = 0; ind < modes; ind++)
isvalid = (isvalid && models[ind]->isValid());
return isvalid;
}
std::vector<double> multimode::fullMap()
{
//Map the model coefficients to a vector of doubles
...
}
void multimode::fullMap(std::vector<double> &data)
{
//Map a vector of doubles to the model coefficients
...
}
and genericBoxModel is an abstract class that all box models are based on.
The curvefit::fit function does the optimization based on the options passed to it:
curveFit^ curveFit::fit(System::ComponentModel::BackgroundWorker^ worker, System::ComponentModel::DoWorkEventArgs^ e, Options^ opts)
{
fcndelegate^ del = gcnew fcndelegate(this, &curveFit::fcn);
std::vector<double> data;
CurrentState^ state = gcnew CurrentState;
state->done = false;
state->stage = 0;
state->percentage = 0;
state->systemModel = systemModel;
worker->ReportProgress(state->percentage, state);
switch(opts->optimizationMethod)
{
case 0:
while(iterationNo < maxIterations)
{
data = systemModel.MapData();
OptimizationMethod0::step(some_parameters, data, (optmethods::costfunction)Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(del).ToPointer());
systemModel.MapData(data);
iterationNo++;
state->percentage = 0;
state->systemModel = systemModel;
worker->ReportProgress(state->percentage, state);
}
...
}
}
I'm passing the system model inside the state so that I can display the results of the
latest step on the screen, which doesn't work, but that is another question :-)
The start button calls the curvefit::fit function after initializing the system model:
private: System::Void btnStart_Click(System::Object^ sender, System::EventArgs^ e) {
systemModel.Clear();
for(int mode = 0; mode < modes; mode++)
{
switch(model)
{
case 0:
systemModel.Add(gcnew model0);
systemModel[mode]->coefficients[0] = 100.0 / double(mode + 1);
...
break;
...
}
}
btnStart->Enabled = false;
stStatusText->Text = "Calculating!";
Application::UseWaitCursor = true;
curveFit^ cf = gcnew curveFit;
fitCurve->RunWorkerAsync(cf);
}
private: System::Void fitCurve_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
System::ComponentModel::BackgroundWorker^ worker;
worker = dynamic_cast<System::ComponentModel::BackgroundWorker^>(sender);
curveFit^ cf = safe_cast<curveFit^>(e->Argument);
cf->expExcitations = gcnew array<double>(expExcitations.Count);
expExcitations.CopyTo(cf->expExcitations);
cf->expResults = gcnew array<double>(expResults.Count);
expResults.CopyTo(cf->expResults);
cf->systemModel = systemModel;
cf->modes = modes;
e->Result = cf->fit(worker, e, options);
}
This works perfectly! But, in order to make the optimization process faster and more
successful, I wanted to use the results of previous optimizations as the initial guess
for the next run (if possible):
multimode oldmodel(systemModel);
systemModel.Clear();
for(int mode = 0; mode < modes; mode++)
{
switch(model)
{
case 0:
if(mode < oldmodel.modeNo() && oldmodel.isValid() && (oldmodel[mode]->model == 0))
systemModel.Add(oldmodel[mode]);
else
{
systemModel.Add(gcnew model0);
systemModel[mode]->coefficients[0] = 100.0 / double(mode + 1);
...
}
break;
...
Now, my problem is, after this change, it seems that the messages don't get passed
correctly: the first time the start button is clicked everything functions as it should,
but from then on, if the statement systemModel.Add(oldmodel[mode]); gets executed,
results remain the same as the initial guesses, and don't get updated after the fit
function is called.
So, why should these two lines(Add(oldmodel[mode]) and Add(gcnew model0)) give
such different results?
Related
Basically, when overloading operator (operator--) constructor is called
my program crashes, changing classes arrays from dynamic, to static ones,
solves the problem, why is that?
If classes arrays are change from dynamic to static, overloading works
great, but this isn't a solution I am looking for.
The working version with static array:
#include <iostream>
#include<string>
using namespace std;
const int TABLE = 10;
class Player()
{
private:
int health;
string A[TABLE][TABLE];
public:
Player()
{
health = 17;
for (int i = 0; i < TABLE; i++)
{
for (int j = 0; j < TABLE; j++)
A[i][j] = "-";
}
}
Player(int new_health)
{
health = new_health;
}
Player operator--()
{
health--;
return Player(health);
}
~Player(){}
};
int main()
{
Player p1; // Creates object p1 and calls Player(), initializing
health variable, and string A array.
--p1; // Decrements p1 health value
return 0;
}
Dynamic array version:
#include <iostream>
#include<string>
using namespace std;
const int TABLE = 10;
class Player()
{
private:
int health;
string **A;
public:
Player()
{
health = 17;
A = new string*[TABLE];
for (int i = 0; i < TABLE; i++)
{
A[i] = new string[TABLE];
}
for (int i = 0; i < TABLE; i++)
{
for (int j = 0; j < TABLE; j++)
A[i][j] = "-";
}
}
Player(int new_health)
{
health = new_health;
}
Player operator--()
{
health--;
return Player(health);
}
~Player()
{
for (int i = 0; i < TABLE; i++)
delete[] A[i];
delete[] A;
}
};
int main()
{
Player p1; // Creates object p1, calls Player(), set health value,
initializes dynamic array
--p1; // Produces a crash with exit status -1
return 0;
}
No error messages, the crash doesn't happen at the health = new_health
part, it crashes as soon as Player(int new_health) constructor has done
its job. How can dynamic arrays affect overloading constructor and cause a crash?
The error is occurring because the new player instance that you create in your -- overload is getting destructed; however, your constructor overload never initialized your dynamic array. So when the destructor is called you are trying to delete unallocated memory.
I have created an MFC dialog based application to study tab control. In a tab control it is possible to set application specific data to each tab.
I am trying to understand how to set/retrieve the data for individual tabs of the tab control.
Here is a sample application I am creating. Each tab of the control is supposed to store some GPU info.
As I understand, there are 3 steps to add application specific data.
Create a user defined structure, whose 1st member should be of type TCITEMHEADER.
struct GPU {
std::wstring name;
int busid;
};
struct tabData {
TCITEMHEADER tabItemHeader;
GPU gpu;
};
Tell the tab control about the extra bytes, the user defined structure is going to take. This I am doing in DoDataExchange().
int extraBytes = sizeof(tabData) - sizeof(TCITEMHEADER);
auto status = tabCtrl1.SetItemExtra(extraBytes);
Set user defined data while adding tabs.
static int tabCtr = 0;
tabData td;
td.tabItemHeader.pszText = _T("TabX");
td.tabItemHeader.mask = TCIF_TEXT;
td.gpu.name = L"AMD NVIDIA";
td.gpu.busid = 101;
TabCtrl_InsertItem(tabCtrl1.GetSafeHwnd(), tabCtr, &td);
Now to get the data, we simply have to call TabCtrl_GetItem().
tabData td2;
td2.tabItemHeader.pszText = new TCHAR[20];
td2.tabItemHeader.cchTextMax = 20;
td2.tabItemHeader.mask = TCIF_TEXT;
td2.gpu.busid = 0;
TabCtrl_GetItem(tabCtrl1.GetSafeHwnd(), 0, &td2);
But as we can see in the following image. I do get the tab text (pszText member - data Item 1 in image), but not the extra data that I had associated with it previously (Data Items 2 and 3 in image).
Which step am I missing?
Why is the structure associated with application defined data not getting populated?
Additional Info
Here is the complete code for the application.
CPP File:
// tabCtrlStackOverflowDlg.cpp : implementation file
//
#include "stdafx.h"
#include "tabCtrlStackOverflow.h"
#include "tabCtrlStackOverflowDlg.h"
#include "afxdialogex.h"
#include <string>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
struct GPU {
std::wstring name;
int busid;
};
struct tabData
{
TCITEMHEADER tabItemHeader;
GPU gpu;
};
CtabCtrlStackOverflowDlg::CtabCtrlStackOverflowDlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_TABCTRLSTACKOVERFLOW_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CtabCtrlStackOverflowDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_TAB1, tabCtrl1);
int extraBytes = sizeof(tabData) - sizeof(TCITEMHEADER);
auto status = tabCtrl1.SetItemExtra(extraBytes);
wchar_t *t = status ? L"SetItemExtra() success" : L"SetItemExtra() fail";
GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(t);
}
BEGIN_MESSAGE_MAP(CtabCtrlStackOverflowDlg, CDialogEx)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDADDTAB, &CtabCtrlStackOverflowDlg::OnBnClickedAddtab)
ON_BN_CLICKED(IDC_GETITEM0, &CtabCtrlStackOverflowDlg::OnBnClickedGetitem0)
ON_BN_CLICKED(IDCLOSE, &CtabCtrlStackOverflowDlg::OnBnClickedClose)
END_MESSAGE_MAP()
// CtabCtrlStackOverflowDlg message handlers
BOOL CtabCtrlStackOverflowDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
return TRUE; // return TRUE unless you set the focus to a control
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CtabCtrlStackOverflowDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
// The system calls this function to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CtabCtrlStackOverflowDlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void CtabCtrlStackOverflowDlg::OnBnClickedAddtab()
{
static int tabCtr = 0;
tabData td;
td.tabItemHeader.pszText = _T("TabX");
td.tabItemHeader.mask = TCIF_TEXT;
td.gpu.name = L"AMD NVIDIA";
td.gpu.busid = 101;
int status = TabCtrl_InsertItem(tabCtrl1.GetSafeHwnd(), tabCtr, &td);
wchar_t *t = L"";
if (status == -1)
{
t = L"TabCtrl_InsertItem() Fail";
}
else
{
t = L"TabCtrl_InsertItem() success";
}
GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(t);
tabCtr++;
}
void CtabCtrlStackOverflowDlg::OnBnClickedGetitem0()
{
tabData td2;
td2.tabItemHeader.pszText = new TCHAR[20];
td2.tabItemHeader.cchTextMax = 20;
td2.tabItemHeader.mask = TCIF_TEXT;
td2.gpu.busid = 0;
if (TabCtrl_GetItem(tabCtrl1.GetSafeHwnd(), 0, &td2) == TRUE)
{
std::wstring text = td2.tabItemHeader.pszText;
text += std::wstring(L" ") + td2.gpu.name;
GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(text.c_str());
}
else
{
GetDlgItem(IDC_STATUSTEXT)->SetWindowTextW(_T("TabCtrl_GetItem()
error"));
}
}
void CtabCtrlStackOverflowDlg::OnBnClickedClose()
{
CDialog::OnCancel();
}
Header File:
// tabCtrlStackOverflowDlg.h : header file
//
#pragma once
#include "afxcmn.h"
// CtabCtrlStackOverflowDlg dialog
class CtabCtrlStackOverflowDlg : public CDialogEx
{
// Construction
public:
CtabCtrlStackOverflowDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_TABCTRLSTACKOVERFLOW_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
// Implementation
protected:
HICON m_hIcon;
// Generated message map functions
virtual BOOL OnInitDialog();
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CTabCtrl tabCtrl1;
afx_msg void OnBnClickedAddtab();
afx_msg void OnBnClickedGetitem0();
afx_msg void OnBnClickedClose();
};
Solution Summary
From Barmak Shemirani's answer here are the 3 reasons my code wasn't working. Must read his answer for better understanding.
TCIF_PARAM must be set in mask, while doing TCM_INSERTITEM, and TCM_GETITEM.
I was using local variables created on stack (tabData td2; object). The reference to this variable was becoming invalid as soon as it was going out of scope.
Using std::wstring in the structure being used for TCM_INSERTITEM. It is better to use data types whose size can be accurately be determined (like plain old data types.).
As Barmak Shemirani points out in comments, the documentation for TCITEMHEADER is scarce. His answer provides a thorough explanation.
Conflict with documentation
Documentation for TCITEMHEADER does not mention using TCIF_PARAM flag. Maybe that's a mistake in documention!
It's better if SetItemExtra is moved to OnInitDialog after default procedure is called. This ensures SetItemExtra is called only once when control is empty.
The structure GPU has a std::wstring member whose data size is unknown at the start. TCM_INSERTITEM cannot make a copy of this data unless you have a simple POD structure.
To store the data in the tab, replace std::wstring with wchar_t name[100] so that data is a simple POD structure with fixed size.
struct GPU
{
//std::wstring name;
wchar_t name[100];
int busid;
};
struct tabData
{
TCITEMHEADER tabItemHeader;
GPU gpu;
};
void CMyDialog::OnBnClickedAddtab()
{
int index = tab.GetItemCount();
wchar_t tabname[50];
wsprintf(tabname, L"Tab %d", index);
tabData sdata = { 0 };
sdata.tabItemHeader.mask = TCIF_TEXT | TCIF_PARAM;
sdata.tabItemHeader.pszText = tabname;
wsprintf(sdata.gpu.name, L"AMD NVIDIA %d", index);
sdata.gpu.busid = 101;
tab.SendMessage(TCM_INSERTITEM, index, (LPARAM)(TCITEMHEADER*)(&sdata));
}
void CMyDialog::OnBnClickedGetitem0()
{
int index = tab.GetCurSel();
tabData data = { 0 };
wchar_t buf[20] = { 0 };
data.tabItemHeader.pszText = buf;
data.tabItemHeader.cchTextMax = sizeof(buf)/sizeof(wchar_t);
data.tabItemHeader.mask = TCIF_TEXT | TCIF_PARAM;
if(tab.SendMessage(TCM_GETITEM, index, (LPARAM)(TCITEMHEADER*)(&data)))
{
CString str;
str.Format(L"%d %s", data.gpu.busid, data.gpu.name);
GetDlgItem(IDC_STATIC1)->SetWindowText(str);
}
}
Alternative method:
If std::wstring name; cannot be replaced with wchar_t buffer, we have to define a separate permanent data, for example using std::vector. Then we use the lParam value in TCITEM to point to the vector.
This method only needs the standard 4 bytes of lParam, it doesn't require TCITEMHEADER and SetItemExtra. You can even define std::vector<GPU>. Example:
std::vector<tabData> m_data;
BOOL CMyDialog::OnInitDialog()
{
CDialogEx::OnInitDialog();
tabData data;
data.gpu.name = L"AMD NVIDIA1";
data.gpu.busid = 101;
m_data.push_back(data);
data.gpu.name = L"AMD NVIDIA2";
data.gpu.busid = 102;
m_data.push_back(data);
return TRUE;
}
void CMyDialog::OnBnClickedAddtab()
{
static int tabCtr = 0;
if(tabCtr >= (int)m_data.size())
return;
TCITEM item = { 0 };
item.pszText = _T("TabX");
item.mask = TCIF_TEXT | TCIF_PARAM;
item.lParam = (LPARAM)&m_data[tabCtr];
tab.InsertItem(tabCtr, &item);
tabCtr++;
}
void CMyDialog::OnBnClickedGetitem0()
{
TCITEM item = { 0 };
item.mask = TCIF_TEXT | TCIF_PARAM;
if(tab.GetItem(tab.GetCurSel(), &item) == TRUE)
{
tabData* ptr = (tabData*)item.lParam;
CString str;
str.Format(L"%d %s", ptr->gpu.busid, ptr->gpu.name.c_str());
GetDlgItem(IDC_STATIC1)->SetWindowText(str);
}
}
I have the following:
//in Matrix.h
class Matrix
{
public:
Matrix (int _row1=1, int _col1=1);
Matrix(const Matrix &);
~Matrix();
int row1;
//int row2;
int col1;
double **m;
//other functions and members...
void Print(int id);
}
//In Matrix.cpp
Matrix::Matrix(int _row1, int _col1): row1(_row1),col1(_col1)
{
m=(double **) new double[row1];
for(long p=0;p<row1;p++) m[p]=(double *) new double[col1];
for(long p=0;p<row1;p++) for (long q=0;q<col1;q++) m[p][q]=0.0;
}
//copy constructor
Matrix::Matrix(const Matrix &Mat){
m=(double **) new double[row1];
**m=**Mat.m;// copy the value
}
// Destructor
Matrix::~Matrix(void){
//We need to deallocate our buffer
delete[] *m;
delete [] m;
//Set m to null just in case
m=0;
cout<<" Freeing m "<<endl;
}
void Matrix::Print(int id)
{
cout<<"Element ID: "<<id<<endl;
for(int i=0; i<row1; i++) {
for(int j=0;j<col1;j++) {
cout<<m[i][j];
if(j==col1-1) cout<<"\n";
}
}
system("PAUSE");
}
a call like the following:
elem[e].d0 = matel[i].OrgD;// Both Matrix
elem[e].d0.Print(1); // checking to see if at all copied
fails at:
void Matrix::Print(int id){
//...
cout<<m[i][j];//here
...//
}
in fact it fails where ever m[i][j] is used by other functions.
this only happens if any object is used successively. And this error goes away if I comment
out the destructor. I fail to understand? Any help!
EDIT 1: I have changed the copy constructor to:
Matrix::Matrix(const Matrix &Mat):row1(Mat.row1),col1(Mat.col1)
{
m= new double *[row1];
for(long p=0;p<row1;p++) m[p]=new double [col1];
for(long p=0;p<row1;p++)for (long q=0;q<col1;q++) m[p][q]=Mat.m[p][q];
// copy the Value
}
And have a assignment operator as:
Matrix& Matrix::operator = (const Matrix& o) {
if ( this == &o ) {
return *this; //Self assignment : nothing to do
}
delete[] *m;
delete[] m;
row1 = o.row1;
col1 = o.col1;
m = new double*[row1];
for(long p=0;p<row1;p++) m[p]=new double [col1];
for(long p=0;p<row1;p++) for (long q=0;q<col1;q++) m[p][q]=o.m[p][q];
return *this;
}
Now it fails at:
Matrix::Operator=...
{
o.m[p] 0xcdcdcdcd double *
CXX0030: Error: expression cannot be evaluated // in the debugger
}
I have noticed that the same thing happens form all functions that use '.m' that is m of the calling object is not available if there is the destructor deleting 'm'. Hope to get some answers.
In your constructor you are using
m=(double **) new double[row1];
for(long p=0;p<row1;p++) m[p]=(double *) new double[col1];
new double[row1] is of type double[]. You cast this to double**. You should use new (double*)[row1] here if you really want to get an array of double pointers.
I appreciate any help, and would like to thank you in advance. I'm working on a project for one of my classes. Essentially performing merge sort using multithreading and reference classes. In main I'm just trying to create an initial thread that will begin the recursive mergesort. Each time the array is split a new thread is spawned to handle that subroutine. I don't need all of it done, i just don't under stand why my Thread constructor and ThreadStart delegate are not working. Thanks again!!
#include <iostream>
#include <vector>
#include <string>
#include <time.h>
#include <cstdlib>
using namespace System;
using namespace System::Threading;
public ref class MergeSort
{
private: int cnt;
public: MergeSort()
{
cnt = 0;
}
public: void mergeSort(char a[], int from, int to)
{
Thread^ current = Thread::CurrentThread;
if(from == to)
return;
int mid = (from + to)/2;
//Sort the first and the second half
//addThread(a, from, mid);
//addThread(a, mid+1, to);
//threads[0]->Join();
//threads[1]->Join();
merge(a, from, mid, to);
}
public: void merge(char a[], int from, int mid, int to)
{
Thread^ current = Thread::CurrentThread;
while (current ->ThreadState == ThreadState::Running)
{
int n = to-from + 1; // Size of range to be merged
std::vector<char> b(n);
int i1 = from; //Next element to consider in the first half
int i2 = mid + 1; //Next element to consider in the second half
int j = 0; //Next open position in b
//As long as neight i1 or i2 is past the end, move the smaller element into b
while(i1 <= mid && i2 <= to)
{
if(a[i1] < a[i2])
{
b[j] = a[i1];
i1++;
}
else
{
b[j] = a[i2];
i2++;
}
j++;
}
//Copy any remaining entries of the first half
while(i1 <= mid)
{
b[j] = a[i1];
i1++;
j++;
}
while(i2 <= to)
{
b[j] = a[i2];
i2++;
j++;
}
//Copy back from temporary vector
for(j = 0; j < n; j++)
a[from+j] = b[j];
}
}
};
void main()
{
char A[10];
for(int i = 0; i < 10; i++)
{
A[i] = ((char) ((rand() % (122-65)) + 65));
}
array<Thread^>^ tr = gcnew array<Thread^>(10);
MergeSort^ ms1 = gcnew MergeSort();
ThreadStart^ TS = gcnew ThreadStart(ms1, &MergeSort::mergeSort(A, 0, 10));
tr[0] = gcnew Thread(TS);
tr[0] -> Start();
system("pause");
}
The issue you are facing here is how to construct a ThreadStart delegate. You are trying to do too many things in the ThreadStart constructor. You cannot pass in arguments at this point because all it is looking for is a start location for the thread.
The delegate should be:
ThreadStart^ TS = gcnew ThreadStart(ms1, &MergeSort::mergeSort);
Since however you are passing in some state, I would recommend doing a bit more research on how that is done using C++\CLI. This MSDN topic should give you a start.
Edit:
Never mind, the problem was that I had to change the parameter of the method I tried to pass from Int32 to Object^.
I´m having a similar issue, though i think my problem are not the arguments. I´m passing those through during thread->Start().
I think my problem is rather that I´m trying to start the thread using a method of a ref class.
invalid delegate initializer -- function does not match the delegate type
Is the error I´m getting. Any Ideas?
void AddForcesAll() {
for (int index = 0; index < n; index++) {
Thread^ thread = gcnew Thread (gcnew ParameterizedThreadStart(this, &Bodies::AddForces));
thread->Start(index);
}
The Syntax worked fine for me for non referenced classes.
Modified the below circular queue code for my app.
This queue can hold 32 elements max and I have declared the elements as a structure array inside the class. For adding an element to the queue you have to call CreateElement() functions, which checks for a free element and returns an index. When I reuse an element after processing the following line in the CreateElement functions crashes
boost::shared_array<char> tData(new char[bufferSize]);
m_QueueStructure[queueElems].data = tData;
As per documentation, the assignment operator is supposed to destroy the earlier object and assign the new one. Why is it crashing? Can someone tell me where am I screwing?
#include "boost/thread/condition.hpp"
#include "boost/smart_ptr/shared_array.hpp"
#include <queue>
#define MAX_QUEUE_ELEMENTS 32
typedef struct queue_elem
{
bool inUse;
int index;
int packetType;
unsigned long compressedLength;
unsigned long uncompressedLength;
boost::shared_array<char> data;
}Data;
class CQueue
{
private:
int m_CurrentElementsOfQueue;
std::queue<Data> the_queue;
mutable boost::mutex the_mutex;
boost::condition_variable the_condition_variable;
Data m_QueueStructure[MAX_QUEUE_ELEMENTS];
public:
CQueue()
{
m_CurrentElementsOfQueue = 0;
for(int i = 0; i < MAX_QUEUE_ELEMENTS; i++)
{
m_QueueStructure[i].inUse = false;
m_QueueStructure[i].index = i;
}
}
~CQueue()
{
for(int i = 0; i < m_CurrentElementsOfQueue; i++)
{
int index = wait_and_pop();
Data& popped_value = m_QueueStructure[index];
popped_value.inUse = false;
}
m_CurrentElementsOfQueue = 0;
}
void push(Data const& data)
{
boost::mutex::scoped_lock lock(the_mutex);
the_queue.push(data);
lock.unlock();
the_condition_variable.notify_one();
}
bool empty() const
{
boost::mutex::scoped_lock lock(the_mutex);
return the_queue.empty();
}
bool try_pop(Data& popped_value)
{
boost::mutex::scoped_lock lock(the_mutex);
if(the_queue.empty())
{
return false;
}
popped_value=the_queue.front();
the_queue.pop();
return true;
}
int wait_and_pop()
{
boost::mutex::scoped_lock lock(the_mutex);
while(the_queue.empty())
{
the_condition_variable.wait(lock);
}
Data& popped_value=the_queue.front();
the_queue.pop();
return popped_value.index;
}
int CreateElement(int bufferSize, unsigned long _compressedLength,
unsigned long _uncompressedLength, int _packetType) /* Send data length for this function */
{
int queueElems = 0;
if(m_CurrentElementsOfQueue == 32)
{
CCommonException ex(QERROR, QUEUE_FULL, "Circular Buffer Queue is full");
throw ex;
}
for(queueElems = 0; queueElems < MAX_QUEUE_ELEMENTS; queueElems++)
{
if(m_QueueStructure[queueElems].inUse == false)
break;
}
boost::shared_array<char> tData(new char[bufferSize]);
m_QueueStructure[queueElems].data = tData;
m_QueueStructure[queueElems].inUse = true;
m_QueueStructure[queueElems].compressedLength = _compressedLength;
m_QueueStructure[queueElems].uncompressedLength = _uncompressedLength;
m_QueueStructure[queueElems].packetType = _packetType;
m_CurrentElementsOfQueue++;
return queueElems;
}
Data& GetElement(int index)
{
Data& DataElement = m_QueueStructure[index];
return DataElement;
}
void ClearElementIndex(Data& delValue)
{
m_CurrentElementsOfQueue--;
delValue.inUse = false;
}
};
for(queueElems = 0; queueElems < MAX_QUEUE_ELEMENTS; queueElems++) after looping queueElems has value 32 but in your m_QueueStructure only 32 elements so you trying to access m_QueueStructure[queueElems].data to 33rd element. That the problem.
EDIT: try use m_QueueStructure[queueElems].data.reset(new char[bufferSize]);
Solved the problem. Two changes I did. In the wait_and_pop function, I was returning an index rather than a Data&. When I returned Data&, that solved the assignment problem. Another crash was happening due to a memset of a shared_array.get(). Lesson learnt, never memset a shared_array or a shared_ptr.