Sign in to follow this  

c++ map usage

This topic is 3485 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi everyone; I designed a database to store may error descriptions. And than when i start my program , it gets errorId s and ErrorDescriptions from databases and store them in the map container to use during program execution. Seemingly it works well. When i debug this code and trace sql query, function works well and gets what i want and send them in the map, associative container. int DB_GetErrorIds( map<int,char*> *errorMap ,int *iErrCode,struct DBCONN *DbConn) { char stSQL[1000]=""; char stErrLog[1000]=""; char sErrorString[50]; int errorId=0; int index=1; long ifNull=0; int rcSQLFetch=0,rcGetError=0; int rcConvertTagsToTable=0; sprintf(stSQL," SELECT ErrorId , ErrorString FROM ErrorManagement "); ExecuteStmt(DbConn,stSQL); SQLBindCol(DbConn->hstmt,index++, SQL_C_LONG,&errorId,0,&ifNull); SQLBindCol(DbConn->hstmt,index++, SQL_C_CHAR,sErrorString,50,&ifNull); while (((rcSQLFetch=SQLFetch(DbConn->hstmt)) == SQL_SUCCESS) || (rcSQLFetch == SQL_SUCCESS_WITH_INFO)) { rcGetError=GetError(rcSQLFetch); if(!((rcGetError==SQL_SUCCESS) || (rcGetError==SQL_SUCCESS_WITH_INFO))) { sprintf(stErrLog,"%s",stSQL); ErrorLog(stErrLog); SQLCloseCursor(DbConn->hstmt); (*iErrCode)=ERR_ISSUER_SYSTEM_KEYS_TABLE_ID; return (*iErrCode); } else { if(strcmp(sErrorString,"")==0) return ERR_INVALID_ERROR_STR; if(errorId==0) return ERR_INVALID_ERROR_ID; //this cause the problem imo (*errorMap).insert(pair<int, char*>(errorId, sErrorString)); } } SQLCloseCursor(DbConn->hstmt); return SUCCEDED; } When my program get out of this function, i want to use my map . Code: for( itt = MyErrorMap.begin() ; itt != MyErrorMap.end(); itt++) { pep = (*itt).first ; if(pep == 123) memcpy(er1,(*itt).second ,sizeof((*itt).second ) + 1); if(pep == 404) memcpy(er2,(*itt).second ,sizeof((*itt).second ) + 1); if(pep == 1001) memcpy(er3,(*itt).second ,sizeof((*itt).second ) + 1); } I see in trace mode , variable pep chancing but variables er1, er2 and er3 are the same, my error tables last entry . I always get the database table's last entry. I think this comes from my DB_GetErrorIds function's localy defined sErrorString variable. Maybe maps lost the sErrorString adresses when i get out of my function. How i overcome this problem.

Share this post


Link to post
Share on other sites
You are correct. The map ends up holding a pointer to memory that was allocated (on the stack) inside a function. When the function exits, the memory is no longer valid (I'm not sure if that is what's causing the problem, but it's an error nonetheless).

The simplest solution is to use std::string instead of character arrays.

Share this post


Link to post
Share on other sites
I second what Gage64 said.

Plus, your usage of sizeof() wouldn't achieve the results you're expecting.

char *x;
sizeof(*x) == 1 // always.


By all means, use std::string. You wouldn't waste 1000 bytes of stack space and you'd get rid of the arbitrary limit on the string length at the same time.

Share this post


Link to post
Share on other sites
I noticed the situation, maps use already allocated memory :). I cant use std::string because this project is a big C project, it is too hard to inject std::string everywhere. I find another solution with char arrays and it works ;)
And i noticed
sizeof(*x) == 4 // always.
because sizeof take an adress in this line

Thanks for your help , Cygon and Gage64 .

Share this post


Link to post
Share on other sites
Quote:
Original post by Ahmet
I noticed the situation, maps use already allocated memory :). I cant use std::string because this project is a big C project, it is too hard to inject std::string everywhere. I find another solution with char arrays and it works ;)
And i noticed
sizeof(*x) == 4 // always.
because sizeof take an adress in this line

Thanks for your help , Cygon and Gage64 .


You can mix and match std::map<int, std::string> with C-style char pointers. An example:

typedef std::map<int, std::string> IntStringMap;
IntStringMap myMap;

extern "C" void addSomething(int key, const char *name) {
myMap.insert(IntStringMap::value_type(key, name));
}

extern "C" BOOL getSomething(int key, char *outValue, int maxLength) {
IntStringMap::const_iterator it = myMap.find(key);
if(it->second.length( + 1) > maxLength)
return FALSE;

memcpy(outValue, it->second.c_str(), it->second.length());
outValue[it->second.length()] = 0;

return TRUE;
}

As a side note, this piece of code seems quite funky:
  char stSQL[1000]="";
sprintf(stSQL," SELECT ErrorId , ErrorString FROM ErrorManagement ");
ExecuteStmt(DbConn,stSQL);
If ExecuteStmt() is under your control, just make it const-correct -> ExecuteStmt(struct DBCONN *DbConn, const char *statement) { /* ... */ }. You can then avoid the unnecessary memory copy and just write:
  ExecuteStmt(DbConn, " SELECT ErrorId , ErrorString FROM ErrorManagement ");

Share this post


Link to post
Share on other sites
Your solution is a very clever solution.
My code is not funky, sometimes i insert in my sql queries integer values with sprintf(stSQL,"SELECT ErrorId FROM ErrorManagement where ErrorId > %d",myInt) ; when "where clause " is needed and it sometimes acts like a template.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ahmet
Your solution is a very clever solution.
My code is not funky, sometimes i insert in my sql queries integer values with sprintf(stSQL,"SELECT ErrorId FROM ErrorManagement where ErrorId > %d",myInt) ; when "where clause " is needed and it sometimes acts like a template.


std::ostringstream stmt(100);
stmt << "SELECT ErrorId FROM ErrorManagement WHERE ErrorId > " << myInt;

Share this post


Link to post
Share on other sites
Or, if you don't mind a bit of magic, you should even be able to do things like:


struct SQLQuery {
std::stringstream query;
DBCONN* connection;
SQLQuery(DBCONN* connection): connection(connection), query() {}

template <typename T>
SQLQuery& operator(const T& item) { query << item; return *this; }

// Assuming we can make ExecuteStmt const-correct
~SQLQuery() { ExecuteStmt(connection, query.str().c_str()); }

private:
SQLQuery(const SQLQuery&);
SQLQuery& operator=(const SQLQuery&);
};

// Create a temporary object, modify it several times using a chaining operator,
// and destroy it implicitly; when destroyed, the SQL query is executed
// implicitly by the object's destructor.
SQLQuery(DbConn)("SELECT ErrorId FROM ErrorManagement WHERE ErrorId > ")(myInt);

Share this post


Link to post
Share on other sites

This topic is 3485 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this