Passing variable NAME to a function - c++

Language: Visual C++, MFC
Environment: Visual Studio 2005
So I posted a similar question, but I've come to realize that I was asking the wrong question. I'm trying to use a loop to call a function on several different variables, but somewhere along the way, the program is crashing.
Simplified code is below, but I think it's actually easier to just explain it. I have a function that takes in a CString as a parameter. I have several variables I wish to feed to this function, so I put their names into an array, and I'm trying to pass them to the function that way.
// THE CODE BELOW IS WHAT I HAVE, BUT IT DOES NOT WORK //
Header File:
CString m_strTop;
CString m_strLeft;
CString m_strRight;
CString m_strBottom;
CString *var[4];
Source File:
Constructor()
CString *var[4] = {
&m_strTop
, &m_strLeft
, &m_strRight
, &m_strBottom
};
Source File:
theFunction()
void myClass::DoDataExchange(CDataExchange* pDX)
{
CSAPrefsSubDlg::DoDataExchange(pDX);
for(int i = 2001, j = 0; i <= 2004; i++, j++)
{
// THE LINE BELOW IS WHERE THINGS GO WONKY, SPECIFICALLY AT &var[j]
DDX_Text(pDX, i, *var[j]); // 'i' is the ID of the textbox
}
}
-- What DDX_Text expects --
void AFXAPI DDX_Text(
CDataExchange* pDX,
int nIDC,
CString& value
);
So like I said, I just need to feed the function the actual name of the variable. At least I think. What it's actually doing is establishing a connection between a text box in a dialog and the variable where the text box's input will be stored. I'm dereferencing correctly and everything, but I don't think this is the right approach.
Thank you for any help. And to people who answered my previous question, my apologies for misrepresenting the issue.

var is an array of pointers to CString.
var[j] is a pointer to CString.
&var[j] is a pointer to pointer to CString.
Now you need to pass the CString object. So you need:
DDX_Text(pDX, i, *var[j]); // dereference a pointer to CString.
Consider using std::vector instead of the C-array. It would be:
std::vector<CString> var(4);
...
DDX_Text(pDX, i, var[j]); // pass a CString object
I've noted that you're declaring variable var once again in the constructor:
CString *var[4] = { // this declares new temporary variable,
// it doesn't initialize one from the header file
&m_strTop
, &m_strLeft
, &m_strRight
, &m_strBottom
};
Shouldn't it be? :
var[0] = &m_strTop;
var[1] = &m_strLeft;
var[2] = &m_strRight;
var[3] = &m_strBottom;
I suppose you need the following:
// header file
class myClass
{
std::vector<CString> var_;
...
};
// source file
myClass::myClass() : var_(4)
{
...
}
void myClass::theFunction(CDataExchange* pDX)
{
CSAPrefsSubDlg::DoDataExchange(pDX);
for(int i = 2001, j = 0; i <= 2004; i++, j++)
{
DDX_Text(pDX, i, var_[j]); // 'i' is the ID of the textbox
}
}

You're not passing the right thing into DDX_Text. It's third parameter is a reference to a CString. You're passing in the address of a pointer. So you should probably do something like
DDX_Test(pDX, i, *var[j]);

Related

Looking for any way to increment ENUM type without operator overloading

so this is about an assignment.
I have a header file with predefined ENUM type (TDay) which I CANNOT change in any way. TDay does not support any operator other than streams.
My problem is I need to find a way to do something like this:
Object::Object (uint aSize) {
Object temp; // contains varible inicialized to zero, this variable can be bool, int, RGB structure
// or TDay enum. I also can't use templates here.
for (int i = 0; i < aSize; i++) {
this->array[i] = temp.Value() + 1; // array is of the same type as Value
}
}
This code is just for illustration of what I need to do, don't look for any use of this I just made it up just to better explain my problem.
So anyway this doesn't work because my TDay doesn't support TDay+int operator.
Is there any way around this? Solution doesn't have to be clean, I'll accept any pointer cheats.
EDIT:
So I tried putting in my Object.cpp file this:
TDay operator+(TDay aDay, int aValue) {
return static_cast<TDay>(int(aDay) + aValue);
}
And it doesn't work. Compiler error says:
Argument of type int is imcompatible with parameter of type TDay
However if I put this code to TDay.h it works fine. Is something wrong with my linker?
I would create a function taking current ENUM value named for example increase
void increase(your_enum& e){
if(e == e::MAX_VAL)
e = e::MIN_VAL; //if you have it, otherwise do same as below
else{
int val = int(e); //cast it to int
val++;
e = static_cast<your_enum>(val); //cast it back
}
}
Creating a function taking another parameter to increase/decrease by more than one should be easy from this point.

VS2010 C++ - Passing Vector of Structures by Reference Not Working as Expected

So I have a perplexing problem that hopefully some of the experts may be able to answer. I have a structure containing structures and vectors containing bitsets. Not going to list all here, but structure definition looks like this:
typedef struct _signal_data_t
{
signal_map_t sigMap;
vector<sigDataType> vSignalData;
vector<sigDataType> vChangeColor;
} signal_data_t;
I declare a vector in my class.
vector<signal_data_t> m_pSignalData;
I then use this vector when calling a function that is expected to fill this vector with all of its information (which it does properly).
CDlgStlFindProcedure mDlgStlFindProcedure(m_pSignalData, m_szVectorFilename);
The class CDlgStlFindProcedure uses pass by reference.
Header file:
CDlgStlFindProcedure(vector<signal_data_t> &pSignalData, CString szInfile, CWnd* pParent = NULL); // standard constructor
Cpp file:
CDlgStlFindProcedure::CDlgStlFindProcedure(vector<signal_data_t> &pSignalData, CString szInfile, CWnd* pParent /*=NULL*/)
: CDialog(CDlgStlFindProcedure::IDD, pParent)
, m_pSignalData(pSignalData)
{
szFilename = szInfile;
}
I set a breakpoint as to when the CDlgStlFindProcedure class finishes, and m_pSignalData is correct. I set a breakpoint as to when it returns, and m_pSignalData is empty. I'm pretty sure I'm using pass by reference correctly as I've used it for a number of items other than vectors. Researching here and other places shows that it should be possible to pass vectors by reference, but it is not working in my application.
I can modify to pass by pointer and then it works, but that seems a clumsier way then passing by reference. Any suggestions? Am I doing something wrong?
Thanks in advance.
edit
I'm getting down voted which I guess means that everyone is thinking this is a stupid question, but I am very confused as to why. Referring to:
https://www.geeksforgeeks.org/passing-vector-function-cpp/
// C++ program to demonstrate how vectors
// can be passed by reference.
#include<bits/stdc++.h>
using namespace std;
// The vect is passed by reference and changes
// made here reflect in main()
void func(vector<int> &vect)
{
vect.push_back(30);
}
int main()
{
vector<int> vect;
vect.push_back(10);
vect.push_back(20);
func(vect);
for (int i=0; i<vect.size(); i++)
cout << vect[i] << " ";
return 0;
}
Output:
10 20 30
How is my usage different than code above?
In your constructor you make copy of vector, not reference.
CDlgStlFindProcedure::CDlgStlFindProcedure(vector<signal_data_t> &pSignalData, CString szInfile, CWnd* pParent /*=NULL*/)
: CDialog(CDlgStlFindProcedure::IDD, pParent)
, m_pSignalData(pSignalData) // copying pSignalData into m_pSignalData
if you really need a reference, do it like this:
vector<signal_data_t> &m_pSignalData;
but remember, it's a very bad style

Vector seemingly changes type dependent on where it's used

EDIT:
The solution:
I tried to create a pointer on a memberfunction and thought the pointer would contain the required informations about the class. It turned out that it didn't.
So Intellisense was absolutely right about the pointer not pointing to an object with the memberfunction but only the memberfunction (or at least that is how I understood it).
In my case I was able to simply use a static member function instead eventhough this function cannot change any memberfunctions without a reference the outer object
Hi and thanks for taking the time to help me.
I'm currently working on some kind of Event-system. I have a class InputManager which checks if the member-function check is called for events the console-window has reveived and then calls the proper event-handlers which are stored in member-function-pointer-vectors (I will later make it a template).
class InputManager
{
private:
HANDLE cursor;
DWORD numEventsCaught, consoleMode, i;
INPUT_RECORD eventBuffer[128];
std::vector<void (InputForm::*)(KEY_EVENT_RECORD)> keyEventHandlers;
std::vector<void (InputForm::*)(MOUSE_EVENT_RECORD)> mouseEventHandlers;
public:
InputManager()
void addKeyEventHandler(void (InputForm::*e)(KEY_EVENT_RECORD));
void addMouseEventHandler(void (InputForm::*e)(MOUSE_EVENT_RECORD));
void check();
};
As you can see, the current type of my vector is a pointer to a member-function of the InputForm-class with a specific parameter. This is also the type that Visual Studio shows me in the little popup-info.
But as soon as I use that vector inside a member-function, the popup-info shows something different and the it tells me that I need to use a pointer-to type.
It tells me that the vector has got the type void (KEY_EVENT_RECORD) instead of void (InputForm::*)(KEY_EVENT_RECORD).
I have no idea how that can happen - i mean how can the type of a vector change just by the scope it's used in?
Here is the function where the problem happens (but it also happens in every other function as well):
void InputManager::check()
{
int size;
if (!ReadConsoleInput(cursor, eventBuffer, 128, &numEventsCaught))
POST_DEBUG_MESSAGE(-1, "Failed to Read Console Input");
for (i = 0; i < numEventsCaught; i++)
{
switch (eventBuffer[i].EventType)
{
case KEY_EVENT:
size = keyEventHandlers.size();
for (int x = 0; x < size; x++)
{
keyEventHandlers[x](eventBuffer[i].Event.KeyEvent); //ERROR ONE
}
break;
case MOUSE_EVENT:
size = mouseEventHandlers.size();
for (int x = 0; x < size; x++)
{
mouseEventHandlers[x](eventBuffer[i].Event.MenuEvent); //ERROR TWO
}
}
}
}
Just in case you want to view all the code, here it is (otherwise just ignore it)
InputManager::InputManager()
{
cursor = GetStdHandle(STD_INPUT_HANDLE);
if (cursor == INVALID_HANDLE_VALUE)
POST_DEBUG_MESSAGE(-1, "Invalid Handle Value, GetStdHandle failed.");
// Deactivate Quickedit
consoleMode = ENABLE_EXTENDED_FLAGS;
if (!SetConsoleMode(cursor, consoleMode))
POST_DEBUG_MESSAGE(-1, "Failed to set Console Mode (Couldn't deactivate Quickedit)");
// Activate mouse and window input
consoleMode = ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT;
if (!SetConsoleMode(cursor, consoleMode))
POST_DEBUG_MESSAGE(-1, "Failed to activate mouse or window inputs");
}
void InputManager::addKeyEventHandler(void (InputForm::*e)(KEY_EVENT_RECORD))
{
keyEventHandlers.push_back(e); // Works properly
}
void InputManager::addMouseEventHandler(void (InputForm::*e)(MOUSE_EVENT_RECORD))
{
mouseEventHandlers.push_back(e);
}
What might be interesting as well is that even if keyEventHandlers.push_back(e) works correctly, it also tells me that e is not member-function-pointer but a usual function pointer -> but the void (InputForm::*e)(KEY_EVENT_RECORD) tells me something else...
I really have no clue what's going on here. Do you have an Idea?
Thank you very much in advance.

Returning a LPWSTR& foo to a function

This point will not work. How to fix it. I understand that the CStrings leave the stack after the call to the function. are the any types of strings i C++ std:strings etc. Thats behave as C# strings. How I get it to work?
void Dialog1::GetOrderingKey(LPWSTR& lpOrderingKey)
{
CString OrderingKey;
m_Result.GetWindowText(OrderingKey);
lpOrderingKey = OrderingKey.GetBuffer(0);
}
LPWSTR lpOrderingKey;
GetOrderingKey(lpOrderingKey);
int returnValue = lpfnDllOrderingCodeDataW(lpSerialNumber, lpOrderingKey, data, _countof(data));
Just return a CString from GetOrderingKey():
CString Dialog1::GetOrderingKey()
{
CString OrderingKey;
m_Result.GetWindowText(OrderingKey);
return OrderingKey;
}
CString ordering_key = GetOrderingKey();
int returnValue = lpfnDllOrderingCodeDataW(lpSerialNumber, (LPCWSTR) ordering_key, data, _countof(data));
One straight forward and simplest way would be to declare it static.
void Dialog1::GetOrderingKey(LPWSTR& lpOrderingKey)
{
static CString OrderingKey;

Copy constructor doesn't work

I have some code that creates an array of documents. Each document object has an array of document-wide values, and an array of individual files (called lines because each is a line in the source file I'm reading from) that together have all the document data. When I attempt to add a document object to the array, it is calling my copy constructor below:
CMyDocument::CMyDocument(CMyDocument& cSourceDoc)
{
m_lpastrFields = new CStringArray;
m_lpacLines = new CArray<CMyLine, CMyLine>;
int nCount;
int nSize;
nSize = static_cast<int>(cSourceDoc.GetFields()->GetSize());
for (nCount = 0; nCount < nSize; nCount++)
{
m_lpastrFields->Add(cSourceDoc.GetFields()->GetAt(nCount));
}
nSize = static_cast<int>(cSourceDoc.GetLines()->GetSize());
for (nCount = 0; nCount < nSize; nCount++)
{
m_lpacLines->Add(cSourceDoc.GetLines()->GetAt(nCount));
}
m_strDocDate = cSourceDoc.GetDocDate();
m_nDocID = cSourceDoc.GetDocID();
m_strDocType = cSourceDoc.GetDocType();
}
The problem is, when I try to access the documents by pulling them from the document array later, the two arrays I've copied above are empty. The seem to be initialized and have memory addresses, but they contain no data. The member variables are populated though. I'm not sure if I'm doing the copying incorrectly or if the problem is elsewhere.
EDIT: The regular constructor looks like this:
CMyDocument::CMyDocument()
{
m_lpastrFields = new CStringArray;
}
I don't new the m_lpacLines object in this case because it is passed into the MyDocument object through a function called InitDocument. I may as well include that here. (Some unnecessary details, like the way I parse the strLine variable to extract all the values, were trimmed for brevity's sake.
void CMyDocument::InitDocument(CMyColumns* lpcColumns, CString strLine, CArray<CMyLine, CMyLine>* lpacLines)
{
CString strValue;
CString strComma = ",";
int nPos = 0;
m_lpacLines = lpacLines;
while (-1 != nPos)
{
strValue = strLine.Tokenize(strComma, nPos);
m_lpastrFields->Add(strValue);
}
m_strDocDate = m_lpastrFields->GetAt(lpcColumns->GetDocDateIndex());
CString strDocID = m_lpastrFields->GetAt(lpcColumns->GetDocIDIndex());
m_nDocID = atoi(strDocID);
m_strDocType = m_lpastrFields->GetAt(lpcColumns->GetDocTypeIndex());
}
And to be clear, I am newing the lpacLines object outside of the InitDocument function every time I loop through. I've already debugged this code though and everything is being assigned correctly here.
SECOND EDIT: In trying to convert these all the non-pointer member variables, I am now coming up against error C2248:'CObject::CObject' : cannot access private member declared in class 'CObject'. Upon reflection, problems like this may have been what pushed me towards using pointers in the first place.
THIRD EDIT: Here is the class declaration:
class CMyDocument
{
public:
CMyDocument();
~CMyDocument();
CMyDocument(CMyDocument& cSourceDoc);
void InitDocument(CMyColumns* lpcColumns, CString strLine, CArray<CMyLine, CMyLine>* lpacLines);
inline CString GetDocDate(void) {return(m_strDocDate);};
inline int GetDocID(void) {return(m_nDocID);};
inline CString GetDocType(void) {return(m_strDocType);};
inline CStringArray* GetFields(void) {return(m_lpastrFields);};
inline CArray<CMyLine, CMyLine>* GetLines(void) {return m_lpacLines;};
private:
CArray<CMyLine, CMyLine>* m_lpacLines;
CStringArray* m_lpastrFields;
CString m_strDocDate;
int m_nDocID;
CString m_strDocType;
};
Now that you've posted the full class definition, it is clear that you are indeed violating the Rule of Three: If you need to explicitly declare either the destructor, copy constructor or copy assignment operator yourself, you probably need to explicitly declare all three of them.
You have a copy constructor, and a destructor, but no copy assignemnt. Add these members and you should be fine.
CMyDocument& operator=(CMyDocument cSourceDoc) {
swap(cSourceDoc);
return *this;
}
void swap(CMyDocument& cSourceDoc) {
using std::swap;
swap(m_lpacLines, cSourceDoc.m_lpacLines);
swap(m_lpastrFields, cSourceDoc.m_lpastrFields);
swap(m_strDocDate, cSourceDoc.m_strDocDate);
swap(m_nDocID, cSourceDoc.m_nDocID);
swap(m_strDocType, cSourceDoc.m_strDocType);
}
Your constructor allocates memory, and makes a member point at it. Somewhere in your code you are making a copy of a CMyDocument. Since you have no copy assignment operator, the compiler uselessly made one for you, that simply copies the pointer, so that you then have two CMyDocument objects pointing at the same CArray and CStringArray. Then, when one of them is deleted, they delete the CArray and CStringArray, and the other CMyDocument is left with useless pointers that point at invalid memory. When you are attempting to use that invalid memory, sometimes, if you get lucky you'll see what used to be there. In this case, the empty CArray and CStringArray. (They empty themselves right as they are deleted). If you weren't lucky, the program would have simply crashed.