I have the following map:
std::map<u_long, std::vector<CChatContainer*> >m_Container;
class CChatContainer
{
public:
CChatContainer()
{
m_uStartPos = 0;
m_uEndPos = 0;
m_dwColor = NULL;
m_pItemElem = NULL;
}
~CChatContainer(){};
u_long m_uStartPos;
u_long m_uEndPos;
DWORD m_dwColor;
void* m_pItemElem;
};
how do I insert values in it, the vector part seems very complex to me
Example:
u_long j = 2; // get index in the map - where to insert
std::vector<CChatContainer*> conts; // create container to insert
for( int i = 0; i < N; i++ ) { // fill the container
CChatContainer* new_cont = new CChatContainer;
cont.push_back(new_cont);
}
m_Container[j] = conts; // insert
Related
All the examples of multimap, yet to find a multi-dimensional example...
System: Visual Studio 2019, C++. Winapi with no extra libraries
Expected result: stores a multi-dimensional array of key/value pairs. Able to pull up a key pair by specifying parent key pairs (similar to hashes in Perl)
Using multimap instead of map since some of the fields have the same header.
Example of my data:
conversationID(int)
|
ConversationType(wstring)
lineID(int)
|
lineType(wstring)
originalLine(wstring)
taggedLine(wstring)
wordID
|
...
Declare the structure:
#include <map>
multimap< int, multimap <int, multimap <wstring, multimap <wstring, multimap <wstring, multimap<wstring, wstring> > > > > > conversation;
multimap< int, multimap <int, multimap <wstring, multimap <wstring, multimap <wstring, multimap<wstring, wstring> > > > > > ::iterator conversationIt;
Try to store some stuff in it... (error: "no instance of overloaded function")
conversation.insert(make_pair<int,int>(2, 1 make_pair<wstring, wstring>(L"originalLine", line)));
Also tried the following but found that multimap does not support [] insert:
conversation[0][0][L"originalLine"][line];
Based on the tree diagram above, the best approach is a simple multidimensional array.
this allows for duplicate "keys"
mixed variable types can be achieve by using supporting tables (see example below)
Compared to other methods:
map does not allow duplicate keys
multimap. could not get this to work. tried for weeks.
class inheritance. does not link sub branches to branches above. it is just a method for exposing variables and methods without having to duplicate your work.
also looked at multisets, vectors, etc.
note: for a large multidimensional array, you will need to use heap memory.
void conversationArray(LPWSTR line)
{
auto conversation = new int[5][10000][100][50]; // conversationID, lineID, objectID, tagid = tag/text
wstring conversationType[3];
auto lineType = new wstring[5][10000]; // conversationID, lineID = string
wstring text[50];
conversationType[0] = L"chat gui";
lineType[0][0] = L"chat";
conversation[0][0][14][12] = 25;
conversation[0][0][15][12] = 30;
lineType[0][1] = L"chat1";
conversation[0][1][15][12] = 500;
lineType[0][2] = L"chat2";
conversation[0][2][15][12] = 60;
conversationType[1] = L"chat gui1";
lineType[1][0] = L"chat-also";
conversation[1][0][15][12] = 33;
// if tag id = 0 then tag is text
conversation[0][0][14][0] = 0;
conversation[0][0][15][0] = 20;
text[0] = line;
text[20] = L"dog";
// print out
int records = 0;
for (int conversationID = 0; conversationID < 5; conversationID++)
{
//sendToReportWindow(L"conversationID: %d\n", conversationID);
for (int lineID = 0; lineID < 10000; lineID++)
{
//sendToReportWindow(L"lineID:%d\n", lineID);
for (int objectID = 0; objectID < 100; objectID++)
{
//sendToReportWindow(L"objectID:%d\n", objectID);
for (int tagID = 0; tagID < 50; tagID++)
{
if (conversation[conversationID][lineID][objectID][tagID] >= 0)
{
if (tagID > 0)
{
sendToReportWindow(L"conversationID:%d type:%s\n", conversationID, conversationType[conversationID].c_str());
sendToReportWindow(L"lineID:%d type:%s\n", lineID, lineType[conversationID][lineID].c_str());
sendToReportWindow(L"conversation[%d][%d][%d][%d]= %d\n", conversationID, lineID, objectID, tagID, conversation[conversationID][lineID][objectID][tagID]);
sendToReportWindow(L"\n");
}
else
{
sendToReportWindow(L"conversationID:%d type:%s\n", conversationID, conversationType[conversationID].c_str());
sendToReportWindow(L"lineID:%d type:%s\n", lineID, lineType[conversationID][lineID].c_str());
sendToReportWindow(L"conversation[%d][%d][%d][%d] text = %s\n", conversationID, lineID, objectID, tagID, text[conversation[conversationID][lineID][objectID][tagID]].c_str());
sendToReportWindow(L"\n");
}
records++;
}
}
}
}
}
sendToReportWindow(L"records:%d\n", records);
sendToReportWindow(L"\n");
// print all records on a specific branch. all lines for conversation 1, line 0
int conversationID = 1; int lineID = 0;
sendToReportWindow(L"Just print a subset of conversation:%d and Line:%d\n", conversationID, lineID);
for (int objectID = 0; objectID < 100; objectID++)
{
for (int tagID = 0; tagID < 50; tagID++)
{
if (conversation[1][0][objectID][tagID] >= 0)
{
if (tagID > 0)
{
sendToReportWindow(L"conversationID:%d type:%s\n", conversationID, conversationType[conversationID].c_str());
sendToReportWindow(L"lineID:%d type:%s\n", lineID, lineType[conversationID][lineID].c_str());
sendToReportWindow(L"conversation[%d][%d][%d][%d]= %d\n", conversationID, lineID, objectID, tagID, conversation[conversationID][lineID][objectID][tagID]);
sendToReportWindow(L"\n");
}
else
{
sendToReportWindow(L"conversationID:%d type:%s\n", conversationID, conversationType[conversationID].c_str());
sendToReportWindow(L"lineID:%d type:%s\n", lineID, lineType[conversationID][lineID].c_str());
sendToReportWindow(L"conversation[%d][%d][%d][%d] text = %s\n", conversationID, lineID, objectID, tagID, text[conversation[conversationID][lineID][objectID][tagID]].c_str());
sendToReportWindow(L"\n");
}
}
}
}
delete[] conversation; delete[] lineType;
}
I have a little complicated data structure but I have a problem with insertion to it, maybe I am thinking wrong.
This data structure is something like (we have a map which is a pair of uint16_t and structure, and three nested structures)
struct Struct4
{
uint8_t struct4ByteData1;
uint8_t struct4ByteData2;
uint16_t struct4ShortIntData1;
uint16_t struct4ShortIntData2;
};
struct Struct3
{
uint32_t struct3IntData1;
uint16_t struct3ShortIntData1;
uint16_t numOfElementsInVectorOfStruct4;
std::string struct3StringData;
std::vector<std::shared_ptr<Struct4>> struct4vector;
};
struct Struct2
{
uint32_t struct2IntData1;
uint16_t struct2ShortIntData1;
uint16_t numOfElementsInVectorOfStruct3;
int16_t struct2ShortIntData2;
std::string struct2StringData;
std::vector<std::shared_ptr<Struct3>> struct3vector;
};
struct Struct1
{
uint32_t struct1IntData1;
uint16_t numOfElementsInVectorOfStruct2;
std::vector<std::shared_ptr<Struct2>> struct2vector;
};
using uint16AndStruct1Map = std::multimap<uint16_t, Struct1>;
And here is a code snippet how data is inserted:
Struct1* struct1_ptr = new Struct1;
std::shared_ptr<Struct2> vectorOfStruct2;
std::shared_ptr<Struct3> vectorOfStruct3;
std::shared_ptr<Struct4> vectorOfStruct4;
uint16AndStruct1Map mapToBeInserted;
bool validData = false;
uint16_t numOfElementsInVectorOfStruct4;
uint16_t status;
uint16_t keyDataFromStruct2;
struct1_ptr->struct1IntData1 = getSomeData();
struct1_ptr->numOfElementsInVectorOfStruct2 = getSomeElements();
if (struct1_ptr->numOfElementsInVectorOfStruct2 == 0)
{
std::cout << "No Pim Avoidance Measurement in This Message, ignore" << std::endl;
return;
}
for(uint16_t i = 0; i < getNumOfElementsOfStruct2(); i++)
{
vectorOfStruct2 = std::make_shared<vectorOfStruct2>();
keyDataFromStruct2 = getKey();
vectorOfStruct2->struct2IntData1 = getSomeData();
vectorOfStruct2->struct2ShortIntData1 = keyDataFromStruct2;
vectorOfStruct2->struct2ShortIntData2 = getSomeData();
vectorOfStruct2->numOfElementsInVectorOfStruct3 = getSomeElements();
vectorOfStruct2->struct2StringData = getSomeStringData();
struct1_ptr->struct2vector.push_back(vectorOfStruct2);
for(uint16_t j = 0; j < getNumOfElementsOfStruct3(); j++)
{
vectorOfStruct3 = std::make_shared<vectorOfStruct3>();
vectorOfStruct3->struct3IntData1 = getSomeData();
vectorOfStruct3->struct3ShortIntData1 = getSomeData();
vectorOfStruct3->numOfElementsInVectorOfStruct4 = getSomeElements();
vectorOfStruct3->struct3StringData = getSomeStringData();
struct1_ptr->struct2vector[i]->struct3vector.push_back(vectorOfStruct3);
numOfElementsInVectorOfStruct4 = getNumOfElementsOfStruct4();
if(numOfElementsInVectorOfStruct4 < 10)
{
for(uint16_t k = 0; k < numOfElementsInVectorOfStruct4; k++)
{
vectorOfStruct4 = std::make_shared<vectorOfStruct4>();
status = getStatus();
if(status == SPECIAL_STATUS_TO_GET_INSIDE_THIS_IF_COND)
{
vectorOfStruct4->struct4ByteData1 = getSomeData();
vectorOfStruct4->struct4ByteData2 = getSomeData();
vectorOfStruct4->struct4ShortIntData1 = getSomeData();
vectorOfStruct4->struct4ShortIntData2 = status;
struct1_ptr->struct2vector[i]->struct3vector->struct4vector.push_back(vectorOfStruct4);
validData = true;
}
}
}
}
if(validData)
{
mapToBeInserted.insert (std::make_pair(keyDataFromStruct2,*struct1_ptr));
}
else
{
for (auto it = mapToBeInserted.begin(); it!=mapToBeInserted.end(); it++)
{
it->second.numOfElementsInVectorOfStruct2--;
}
}
validData = false;
}
After everything was inserted into map (and all of structures), when I want to get data from this map I probably get memory error. I am not 100% sure what the problem is.
The issue occurs at level of obtaining data from the map: mapToBeInserted.
Could you help?
if numOfElementsInVectorOfStruct4 is more than 10 you don't insert anything into struct4vector therefore this loop will access out of the bounds of struct4vector:
for(uint16_t l = 0; l < kv.second.struct2vector[j]->struct3vector[k]->numOfElementsInVectorOfStruct4; l++)
{
ss << "<"
<< kv.second.struct2vector[j]->struct3vector[k]->struct4vector[l]->struct4ByteData1 << ","
There are nothing wrong with the map insertion. The program crashed because of the vector index numOfElementsInVectorOfStruct4.
You have set the number of element :
vectorOfStruct3->numOfElementsInVectorOfStruct4 = getSomeElements();
But the data of struct4vector is inserted with CONDITION (there are two : < 10 and Status is OK)
So that the vector size struct4vector.size() and numOfElementsInVectorOfStruct4 can be different (when numOfElementsInVectorOfStruct4 < 10 and
one of its element has status OK).
Here are some advices :
Work with pointer (with map) to avoid the struct element copy
Work with vector size() function instead of getSomeElements() somewhere.
Check for the map element exists before used
I'm having a problem with the code attached below. Essentially it generates a huge memory leak but I can't see where it happens.
What the code does is receiving an array of strings, called prints, containing numbers (nodes) separated by ',' (ordered by desc number of nodes), finding other compatible prints (compatible means that the other string has no overlapping nodes 0 excluded because every print contains it) and when all nodes are covered it calculates a risk function on the basis of a weighted graph. In the end it retains the solution having the lowest risk.
The problem is that leak you see in the picture. I really can't get where it comes from.
Here's the code:
#include "Analyzer.h"
#define INFINITY 999999999
// functions prototypes
bool areFullyCompatible(int *, int, string);
bool contains(int *, int, int);
bool selectionComplete(int , int);
void extractNodes(string , int *, int &, int);
void addNodes(int *, int &, string);
Analyzer::Analyzer(Graph *graph, string *prints, int printsLen) {
this->graph = graph;
this->prints = prints;
this->printsLen = printsLen;
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
this->bestReSize = INFINITY;
this->bestRisk = INFINITY;
this-> actualSize = -1;
}
void Analyzer::getBestResult(int &size) {
for (int i = 0; i < bestReSize; i++)
cout << bestResult[i] << endl;
}
void Analyzer::analyze() {
// the number of selected paths is at most equal to the number of nodes
int maxSize = this->graph->nodesNum;
float totRisk;
int *actualNodes = new int[maxSize];
int nodesNum;
bool newCycle = true;
for (int i = 0; i < printsLen - 1; i++) {
for (int j = i + 1; j < printsLen; j++) {
// initializing the current selection
if (newCycle) {
newCycle = false;
nodesNum = 0;
extractNodes(prints[i], actualNodes, nodesNum, maxSize);
this->actualResult[0] = prints[i];
this->actualSize = 1;
}
// adding just fully compatible prints
if (areFullyCompatible(actualNodes, nodesNum, prints[j])) {
this->actualResult[actualSize] = prints[j];
actualSize++;
addNodes(actualNodes, nodesNum, prints[j]);
}
if (selectionComplete(nodesNum, maxSize)) {
// it means it's no more a possible best solution with the minimum number of paths
if (actualSize > bestReSize) {
break;
}
// calculating the risk associated to the current selection of prints
totRisk = calculateRisk();
// saving the best result
if (actualSize <= bestReSize && totRisk < bestRisk) {
bestReSize = actualSize;
bestRisk = totRisk;
for(int k=0;k<actualSize; k++)
bestResult[k] = actualResult[k];
}
}
}
newCycle = true;
}
}
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
int nodesNum = 0;
for (int i = 0; i < actualSize; i++) {
extractNodes(this->actualResult[i], nodes, nodesNum, maxSize);
// now nodes containt all the nodes from the print but 0, so I add it (it's already counted but misses)
nodes[nodesNum-1] = 0;
// at this point I use the graph to calculate the risk
for (int i = 0; i < nodesNum - 1; i++) {
float add = this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
totRisk += this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
//cout << "connecting " << nodes[i] << " to " << nodes[i + 1] << " with risk " << add << endl;
}
}
delete nodes;
return totRisk;
}
// -------------- HELP FUNCTIONS--------------
bool areFullyCompatible(int *nodes, int nodesNum, string print) {
char *node;
char *dup;
int tmp;
bool flag = false;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL && !flag)
{
tmp = atoi(node);
if (contains(nodes, nodesNum, tmp))
flag = true;
node = strtok(NULL, ",");
}
// flag signals whether an element in the print is already contained. If it is, there's no full compatibility
if (flag)
return false;
delete dup;
delete node;
return true;
}
// adds the new nodes to the list
void addNodes(int *nodes, int &nodesNum, string print) {
char *node;
char *dup;
int tmp;
// in this case I must add the new nodes to the list
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
if (tmp != 0) {
nodes[nodesNum] = tmp;
nodesNum++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
}
// verifies whether a node is already contained in the nodes list
bool contains(int *nodes, int nodesNum, int node) {
for (int i = 0; i < nodesNum; i++)
if (nodes[i] == node)
return true;
return false;
}
// verifies if there are no more nodes to be added to the list (0 excluded)
bool selectionComplete(int nodesNum, int maxSize) {
return nodesNum == (maxSize-1);
}
// extracts nodes from a print add adds them to the nodes list
void extractNodes(string print, int *nodes, int &nodesNum, int maxSize) {
char *node;
char *dup;
int idx = 0;
int tmp;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
// not adding 0 because every prints contains it
if (tmp != 0) {
nodes[idx] = tmp;
idx++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
nodesNum = idx;
}
You have forgotten to delete several things and used the wrong form of delete for arrays where you have remembered, e.g.
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
//...
delete [] nodes; //<------- DO THIS not delete nodes
The simplest solution is to avoid using raw pointers and use smart ones instead. Or a std::vector if you just want to store stuff somewhere to index into.
You have new without corresponding delete
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
These should be deleted somewhere using delete [] ...
You allocate actualNodes in analyze() but you don't release the memory anywhere:
int *actualNodes = new int[maxSize];
In Addition, Analyzer::bestResult and Analyzer::actualResult are allocated in the constructor of Analyzer but not deallocated anywhere.
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
If you must use pointers, I really suggest to use smart pointers, e.g. std::unique_ptr and/or std::shared_ptr when using C++11 or later, or a Boost equivalent when using C++03 or earlier. Otherwise, using containers, e.g. std::vector is preferred.
PS: You're code also has a lot of mismatches in terms of allocation and deallocation. If memory is allocated using alloc/calloc/strdup... it must be freed using free. If memory is allocated using operator new it must be allocated with operator delete. If memory is allocated using operator new[] it must be allocated with operator delete[]. And I guess you certainly should not delete the return value of strtok.
Every time i use IsertColumn function it will return an int variable. That variable is a index of a column.
If we have a lot of columns, is there any way to get that index of a column with given name (header text of that column).
Thank you
Per your request, something similar to this should work....
This example derives a CListCtrl to be used within a dialog.
int MyListCtrl::FindColumn(const CString& ColumnText)
{
int index = -1;
CHeaderCtrl* pHeader = GetHeaderCtrl();
if (pHeader)
{
int NumberOfColumns = pHeader->GetItemCount();
for (int i = 0; i < NumberOfColumns; ++i)
{
HDITEM Item;
TCHAR buffer[256] = { 0 };
Item.mask = HDI_TEXT;
Item.pszText = buffer;
Item.cchTextMax = 256;
pHeader->GetItem(i, &Item);
if (Item.pszText == ColumnText)
{
index = i;
break;
}
}
}
return index;
}
To call the function:
int index = m_llistctrl.FindColumn(_T("Value"));
Where "Value" is the text of an actual column in the header.
CListCtrl::GetHeaderCtrl::GetItem(int iPos, HDITEM* pHeaderItem);
HDITEM::pszText is what you want - if I got your question correctly...
I know I should know this, but it's late and my brain just won't put the pieces together.
This is as straight forward as a question can get:
I have a struct item. I want to create a pointer to an array of pointers to that item type.
Eg.
struct item {
int data;
string moreData;
};
I want to have an ArrayPointer that point's to an array. I want that array to contain in each element a pointer to an item.
How do I do this in C++, or more sepcifically where do I need to put how many dereferencing operators? I know how to declare basic (single indirection) pointers and am pretty fluent in their use.
I need information for the following steps if at all possible:
Declaring the ArrayPointer.
Initializing the ArrayPointer with a size s.
Initializing each element of ArrayPointer with new item.
eg:
for(int i = 0; i < s; i++)
ArrayPointer[i] = // a new item
I feel like as soon as someone posts an answer I'm going to facepalm so hard I break my nose.
If I have understood correctly then you need something like this
item **ArrayPointer = new item *[s];
for ( int i = 0; i < s; i++ )
{
ArrayPointer[i] = new item; { i, "More Data" };
}
Or
item **ArrayPointer = new item *[s];
for ( int i = 0; i < s; i++ )
{
ArrayPointer[i] = new item;
ArrayPointer[i]->data = i;
ArrayPointer[i]->moreData = "More Data";
}
To free the allocated memory you can in reverse order
for ( int i = 0; i < s; i++ )
{
delete ArrayPointer[i];
}
delete [] ArrayPointer;
Otherewise if s is a constant then you may simply declare an array of pointers. For example
item * ArrayPointer[s];
for ( int i = 0; i < s; i++ )
{
ArrayPointer[i]->data = i;
ArrayPointer[i]->moreData = "More Data";
}
file.h
struct item {
int data;
string moreData;
};
item ** array;
file.cpp
array = new item*[s];
for(int i = 0; i < s; i++)
{
array[i] = new item;
array[i]->data = 10;
array[i]->moreData = "data";
}
What you want is an array of struct item *, which are pointers to item structs.
An array of such pointers is a struct item **.
#include <string>
#include <cstdlib>
using namespace std;
struct item {
int data;
string moreData;
};
struct item * newItem(int data, string moreData) {
struct item *result = (struct item *) malloc(sizeof(struct item));
result->data = data;
result->moreData = moreData;
return result;
}
struct item ** array; // We don't know the size of the array in advance.
int main() {
int arraySize = 3; // We get this value from somewhere (user input?).
array = (struct item **) malloc(3*sizeof(struct item *));
// Now the array has been allocated. There is space for
// arraySize pointers.
array[0] = newItem(5, "ant"); // Let's make some items. Note that
array[1] = newItem(90, "bear"); // newItem() returns a pointer to
array[2] = newItem(25, "cat"); // an item.
return 0;
}