Basic questions: Pointers to objects in unordered_maps (C++) - c++

I'm new to C++ programming and would greatly appreciate replies that don't assume much prior knowledge.
Thanks to suggestions here, I've created an unordered map:
typedef std::tr1::unordered_map<std::string, Strain*> hmap;
The data in this map are pointers to instances of class Strain. As soon as these instances are created, I create pointers to them, and I then add these pointers to my hash table (hmap strainTable) and to another vector (vector< Strain *> liveStrains), e.g.,
string MRCA;
for ( int b = 0; b < SEQ_LENGTH; b++ ) {
int randBase = rgen.uniform(0,NUM_BASES);
MRCA.push_back( BASES[ randBase ] );
}
Strain * firstStrainPtr;
firstStrainPtr = new Strain( idCtr, MRCA, NUM_STEPS );
liveStrains.push_back( firstStrainPtr );
strainTable[ MRCA ]= firstStrainPtr;
Instances of class Strain are never deleted, nor are pointers to them removed from strainTable. Pointers do occasionally move between vector< Strain * > liveStrains and vector< Strain * > deadStrains, but once on strainTable, they stay on strainTable.
Is this kosher? As long as the underlying instances are never destroyed, will the pointers added to them remain intact?
Is it also correct that I should always be able to get member attributes from the pointers in strainTable by using, e.g., for the first entry,
hmap::const_iterator itr1 = strainTable.begin();
int id = (itr1->second)->getStrainID();
I'm finding that after a while, pointers in my strainTable point to garbage.

A pointer to any object allocated with new will remain valid until you call delete on the object. You can copy the pointer as much as you like, and it will be valid as long as the underlying object has not been deleted.
Secondly, yes, you are correct that you can access object attributes from the stored pointers via container iterators. But always check to make sure that the return value of hmap::find() is not equal to hmap::end().
So what you describe is fine. Now, as to why the pointers in your strainTable are ending up pointing to garbage, I couldn't say without more details. Are you sure you're not deleting any objects anywhere? Are you sure that when you copy pointers from one vector to the other, you are doing it correctly?

if you never delete them, then the pointers are still ok. On the other hand, you might want to keep things a bit tidier and use standard containers for the whole shebang.
typedef std::tr1::unordered_map<std::string, Strain> hmap;
typedef std::tr1::unordered_map<std::string, hmap::iterator> weakhmap;
hmap strainTable;
weakhmap liveStrains;
Strain firstStrain( idCtr, MRCA, NUM_STEPS );
strainTable[MRCA] = firstStrain;
liveStrains[MRCA] = strainTable.find(MRCA);

Related

C++ Vectors insert new objects

I'm a self-taught c++ programmer (still at novice level).
I think I got an idea of how c++ works, but I can't wrap my head around this:
I want to create and populate an std::vector with different elements of a defined-by-me class:
// other code
while (getline(cfgDataStream, cfgData)) //parsing cycle of the config file
{
std::stringstream ss(cfgData); //creating a stream in order to fill fields
ss >> string1 >> IP1 >> IP2 >> PORT2 >> INDEX;
//they are all strings save the last one, which is a int
if (ss.fail())
{
//bad things happen
}
//FIRST IDEA: Using insert()
CModbusServer MBtemp* = new CModbusServer(this, IP2.c_str(), PORT2, INDEX)
std::vector<CModbusServer*>::iterator iterator = this->m_pServerCollection.begin(); //I get the vector initial position
m_pServerCollection.insert(iterator + (INDEX), MBTemp); // I put the new object in the right index (I don't trust the order in the config file)
//SECOND IDEA: Using push_back()
m_pServerCollection.push_back( new CModbusServer(this, IP2.c_str(), PORT2, INDEX)); //I attach each new object to the end of vector (i trust the order in the config file)
}
basically I want to create an object of CModbusServer and insert its pointer in a vector, so that I have n different CModbusServer objects in each vector position.
And this is where I get lost, i tried two ways of insertion (as shown in the code ) without success.
CModbusServer has, among others, a const char* ipAddress field. If I try to access to that field (i.e. to use it in a .Format(_T("%S)) function) I get random data. Trying to see why I noticed that in the vector I don't have n different objects,but n copies of the last object created with new CModbusServer(this, IP2.c_str(), PORT2, INDEX). Probably this happens due to the fact that I have a vector of pointers, but those should be pointers to different objects...
I'm using Visual Studio 2015 with MFC in order to realize a dialog-based application. I have an AppEngine class that calls method from other classes and has a vector of CModbusServer elements.
CModbusServer.h is as follows:
class CModbusServer
{
public:
CModbusServer(void *parentEngine, const char* , unsigned short , int );
~CModbusServer();
const char* ipAddress;
unsigned short port;
int indNode;
modbus_t *MBserver;
bool isConnected;
}
So, my question are:
1) Why can't I access to the ipAddress field (instead of reading "192.0.2.1" I read random characters) while I theoretically should be able to read it usingtheApp.CModbusServerVector[properIndex]->ipAddress?
2) I'm making a mistake in populating the vector, but I can't see where and, most importantly, why it's wrong.
Thank you for your assistance, and excuse my english and any omission.
EDIT:
The constructor code of CModbusServer is this:
CModbusServer::CModbusServer(void *pE, const char* ip, unsigned short nport, int ind)
: parentEngine(pE), //used in order to keep track of the parent dialog
ipAddress(ip),
port(nport),
indNode(ind)
{
this->isConnected = false;
this->m_socket = INVALID_SOCKET;
memset(&m_socketstructhint, 0, sizeof m_socketstructhint);
m_socketstructhint.ai_family = AF_UNSPEC;
m_socketstructhint.ai_socktype = SOCK_STREAM;
m_socketstructhint.ai_protocol = IPPROTO_TCP;
MBserver = modbus_new_tcp(ipAddress, (int)nport);
}
Please tell me if I omitted any other useful information.
Initially I used CString for managing the strings, but then I incurred in more and more issues and finally got a compiling and patially working code with const char*. I managed to enstablish a connection and to read the desired modbus registers, but then I got stuck on the isAddress printing problem.
modbus_new_tc(ip,port) is a method found in libmodbus library, a freeware library written for C that I had to use.
EDIT 2: related to angew answer:
So, If I'm right, what's happening is that I create a temporary set of pointers, that are used by the constructor (I've now added the relevant code). But shouldn't be the constructed object unrelated with what I've passed as argument? Aren't those argument copied? Sorry if the question is stupid, but I'm still learning.
the indices are sequential, though in the config file thay could as well be 0-1-2-3 (1 per line) or 0-3-1-2, that's what I meant by "don't trust them".
Since the push_back method has the same issues, probably the problem is back in the constructor. What puzzles me is that by doing a step by step execution I can see that with each iteration of the while loop I get new and correct data, but instad of being put in the i-th position, is put in the first i positions (i.e.: origin data: a b c, 1st run vector = a; 2nd run vector = b b,3rd run vector = c c c)
I didn't know std::unique_ptr<>, i'll look it up.
I've tried to use std:string or even CString, but the problem lies beneath libmodbus libraries.
Calling c_str on a std::string returns a "live" pointer to the internal data stored in that std::string instance. The pointer returned points to a buffer which is only valid as long as the std::string on which it was called remains alive and unmodified.
The constructor of CExtracalModbusServer just stores the pointer passed in. That pointer becomes dangling as soon as IP2 is re-assigned in the next iteration of the input loop. (The address pointed to is still the same, but the buffer which was previously located at that address has either been overwritten, or freed, or something else. In other words, the pointer is just dangling).
As for inserting into the vector: the first way (with insert) could only work if the indices in the files are sequential and starting at 0. You need a valid iterator into the vector to insert into it, where valid here means either pointing to one of the elements already in the vector, or the past-the-end iterator (the one returned by end()). If INDEX is equal to or larger than the size of the vector, then m_pServerCollection.insert(iterator + (INDEX), MBTemp); will attempt to insert outside the vector (essentially a buffer overfow). Ubnefined behaviour ensues.
The push_back way of inserting data should work, and if you see it misbehaving, it's either an artifact of the earlier bug (the one with dangling pointers), or there is a separate problem in code which you haven't shown.
Unrelated to the question at hand, but the code contains pretty bad practice in the form of manually managed dynamic memory. Instead of storing a CModbusServer* in the vector and managing the memory manually with delete in all the right places, you should be using std::unique_ptr<CModbusServer> which will take care of proper deallocation for you, even in the presence of exceptions.
If CModbusServer is under your control, you should likewise change it to store a std::string instead of a const char*. Never use C-style strings in C++ unless you have to interact with C-style APIs, and even in such case, limit their use only to the interaction itself. It's the same principle all over again: don't manage memory manually.

Use of pointer to vector which involved the use of 'new'

I would like to create a vector of pointers to struct
vector<myStruct*> vec
For elements in the vector, not all of them contain data. Some of them may point to NULL.
So, should I create space by new in each of the element first
for(int i = 0; vec.size() ;i++){
if (thisSpaceIsValid(i))
vec.at(i) = new myStruct;
else
vect.at(i) = NULL;
}
The problem comes:
-If I use new for each element, it would be very slow. How can I speed it up a bit? Is there a way the create all the spaces that I need , that automatically access the pointer of such space to the vector(vec here)?
-If later I use delete to free the memory, would the problem of speed still bother me?
If I use "new" for each element, it would be very slow. How can I speed it up a bit? Is there a way the create all the spaces that I need , that automatically access the pointer of such space to the vector("vec" here)?
You can do that.
Let's say the size of your vector is M and you only need N of those elements to have pointers to objects and other elements are null pointers. You can use:
myStruct* objects = new myStruct[N];
and then, use:
for(int i = 0, j = 0; vec.size(); i++)
{
if (thisSpaceIsValid(i))
{
if ( j == N )
{
// Error. Do something.
}
else
{
vec[i] = objects+j;
++j;
}
}
else
{
vect[i] = NULL;
}
}
You have to now make sure that you are able to keep track of the value of objeccts so you can safely deallocate the memory by using
delete [] objects;
PS
There might be a better and more elegant solution to your problem. It will be worth your while to spend a bit more time thinking over that.
EDIT:
After reading the question again, it seems I misunderstood the question. So here is an edited answer.
If you only need to execute the code during some kind of initialization phase, you can create all the instances of myStruct in an array and then just point to those from the vector as already proposed by R Sahu. Note that the solution requires you to create and delete all instances at the same time.
However, if you execute this code several times and/or don't know exactly how many myStruct instances you will need, you could overwrite new and delete for the struct and handle memory allocation yourself.
See Callling object constructor/destructor with a custom allocator for an example of this. See the answer by Jerry Coffin.
BTW - you don't need vec.at(i) as you are iterating from 0 to size. vec[i] is okay and should perform a better.
OLD ANSWER:
You can do
vector<myStruct*> vec(10000, nullptr);
to generate a vector with for instance 10000 elements all initialized to nullptr
After that you can fill the relevant elements with pointer to the struct.
For delete just
for (auto e : vec) delete e;
cause it is safe to do deleteon a nullptr
If you need a vector of pointers, and would like to avoid calling new, then firstly create a container of structs themselves, then assign pointers to the elements into your vec. Be careful with choosing the container of structs. If you use vector of structs, make sure to reserve all elements in advance, otherwise its elements may move to a different memory location when vector grows. Deque on the other hand guarantees its elements don't move.
Multiple small new and delete calls should be avoided if possible in c++ when performance matters a lot.
The more I think about it, the less I like #RSahu's solution. In particular, I feel memory management in this scenario would be a nightmare. Instead I suggest using a vector of unique_ptr's owning memory allocated via custom alloctor. I believe, sequential allocator would do.

std::map with pointers: wrong value assess

I am trying to save into the STL map a pointer to the Block object:
void IO::parseInput(void)
{
map<string, Block*> blocksMap;
//=== Create new block and write it to the vector in database ===
Block tmpBlock (bIndex, bName, bWidth, bHeight);
Block* tmpPointer = db.addBlock(tmpBlock); //addBlock returns pointer to the added Block
tmpPointer->printParams(); // -- here is correct output
blocksMap.insert ( pair<string, Block*>(bName, tmpPointer) );
// === Test hash ===
blocksMap.find("anyLegalStringKey")->second->printParams(); // -- wrong output
}
addBlock function in DB class:
Block* DB::addBlock (Block& newBlock)
{
blocks.push_back(newBlock);
Block* ptrToLast = &blocks.back();
return ptrToLast;
}
Vector of Block's in DB class:
class DB:
{
private:
//=== Database ===
vector <Block> blocks;
};
Problem: Before writing into the map I access to the object (which pointer I want to save) using pointer tmpPointer and print all its parameters. This one works correct. Then I save this pointer in map with specific key. When i try then to access the same pointer using find in map with specific key, I get a wrong output (I also print all parameters).
When I try to access to pointers in map for any existed key it could lead to four different reactions:
Everything is OK and I get normal output (in my case I print all parameters)
I get wrong parameters (e.g. instead of index 7 I got 21814704)
Unreadable output
Segmentation fault
Interesting is that for the same Block object I have always same reaction (e.g. block with name "g22i" has always unreadable output).
Vector "blocks" in db contains correct info before and after I save pointers in map.
Thanks!
You are trying to use long-lived pointers to std::vector's elements. That's a recipe for disaster. All such pointers will be invalidated the very moment your vector decides to reallocate itself.
If you want to use pointers to vector elements, you have to make sure the vector never reallocates. I.e. you have to reserve enough capacity in advance to store all future elements. Most of the time it is suboptimal, defeats the purpose of using std::vector or plain impossible.
You can also use a container that never invalidates pointers to its elements, like std::list. But std::list does not support random access. You can use std::deque, which supports random access (albeit less efficiently than std::vector) and preserves the validity of element pointers as long as you don't insert anything into the middle of the sequence.
Finally, you can keep using std::vector, but make sure to store [smart] pointers to Block objects in it instead of Block objects themselves. The idea is to ensure that vector reallocation does not cause reallocation of the actual Block objects.
P.S. Another remark: when you declare a map<string, Block*> blocksMap, elements of such map have type pair<const string, Block*> (note the extra const). I.e. map<string, Block*>::value_type is actually pair<const string, Block*>.
Later you are trying to call blocksMap.insert with pair<string, Block*> argument, while blocksMap.insert actually expects pair<const string, Block*>. This compiles, but it involves an implicit conversion from your pair<string, Block*> to pair<const string, Block*> performed by std::pair's conversion constructor. This is not optimal performance-wise. Which is why a better idea might be to use map<string, Block*>::value_type instead of trying to spell the element type manually
blocksMap.insert ( map<string, Block*>::value_type(bName, tmpPointer) );

initialization new map and set in c++

Hi i am doing my homeworks and i have a problem.
I need diferents maps and set in the application and i want reuse some variables.
I have this global variables
map<char,set<char> > IAF; //I Am Father
map<char,int> NBM; //Number Before Me
set<char> WCR; //Who can run
and every time in the main i need reset this variables.
I have done two things:
IAF = new map<char,set<char> >;
and
IAF = map<char,set<char> >;
But any has run.
Can someone help me?
use
IAF.clear()
NBM.clear()
WCR.clear()
(Edit: references to the spec and caveats)
map::clear()
set::clear()
Note that if you're storing pointers, clear() will remove the pointers, but it will not delete the memory pointed to by the pointers.
map<char,set<char> > IAF;
This is a definition of variable. This is not a pointer. If you want to do some kind of initialization you can use one of supported methods, e.g:
std::copy( differentContainer.begin(), differentContainer.end(), IAF.begin());
or
while( ...) {
IAF.insert( ...);
// or
IAF[ key] = value;
}
To delete the content of map you can do (this will not automatically delete memory pointed to by pointer in map - if you store pointers, use a smart pointers then):
IAF.clear();
In addition to the previous answers which are fairly clear. The new keyword, that you used at some point, is to allocate memory for a pointer.
map<char, set<char> > *IAF = new map<char, set<char> >;
//...
// free the memory
delete IAF;
Check the Dynamic memory allocation for more information and to understand when and how to use pointers.
Also, using
IAF = map<char,set<char> >;
Is incorrect. The map<char, set<char> > is a class name (combined with templates generic programming, see the answer to What is the meaning of "generic programming" in c++? ) and hence you cannot assign it to a variable in this way. What you want to do is to call the constructor that will return an instance of that class:
IAF = map >();
However, doing it this way is not efficient at all. It creates a temporary object, destroys IAF, copies the temporary, and then destroys the temporary (unless you are using C++11 and in this case you use move, but still...). So, it's better to use the clear() as stated by the other answers.

Why is memory still accessible after std::map::clear() is called?

I am observing strange behaviour of std::map::clear(). This method is supposed to call element's destructor when called, however memory is still accessible after call to clear().
For example:
struct A
{
~A() { x = 0; }
int x;
};
int main( void )
{
std::map< int, A * > my_map;
A *a = new A();
a->x = 5;
my_map.insert( std::make_pair< int, *A >( 0, a ) );
// addresses will be the same, will print 5
std::cout << a << " " << my_map[0] << " " << my_map[0]->x << std::endl;
my_map.clear();
// will be 0
std::cout << a->x << std::endl;
return 0;
}
The question is, why is variable a still accessible after its destructor was called by map::clear()? Do I need to write delete a; after calling my_map.clear() or is it safe to overwrite the contents of a?
Thanks in advance for your help,
sneg
If you store pointers on a map (or a list, or anything like that) YOU are the responsible for deleting the pointers, since the map doesn't know if they have been created with new, or not. The clear function only invokes destructors if you don't use pointers.
Oh, and one more thing: invoking a destructor (or even calling delete) doesn't mean the memory can't be accessed anymore. It only means that you will be accessing garbage if you do.
std::map does not manage the memory pointed to by the pointer values - it's up to you to do it yourself. If you don't want to use smart pointers, you can write a general purpose free & clear function like this:
template <typename M> void FreeClear( M & amap )
for ( typename M::iterator it = amap.begin(); it != amap.end(); ++it ) {
delete it->second;
}
amap.clear();
}
And use it:
std::map< int, A * > my_map;
// populate
FreeClear( my_map )
;
That's because map.clear() calls destructors of the data contained in the map, in your case, of the pointer to a. And this does nothing.
You might want to put some kind of smart pointer in the map for the memory occupied by a to be automatically reclaimed.
BTW, why do you put the template arguments in the call to make_pair? The template argument deduction should do pretty well here.
When you free a piece of heap memory, its contents don't get zeroed. They are merely available for allocation again. Of course you should consider the memory non accessible, because the effects of accessing unallocated memory are undefined.
Actually preventing access to a memory page happens on a lower level, and std libraries don't do that.
When you allocate memory with new, you need to delete it yourself, unless you use a smart pointer.
Any container stores your object Type and call corresponding constructors: internal code each node might look similar to:
__NodePtr
{
*next;
__Ty Val;
}
When you allocate it happens by constructing the val based on type and then linking. Something similar to:
_Ty _Val = _Ty();
_Myhead = _Buynode();
_Construct_n(_Count, _Val);
When you delete it calls corresponding destructors.
When you store references (pointers) it won't call any constructor nor it will destruct.
Having spent the last 2 months eating, sleeping, and breathing maps, I have a recommendation. Let the map allocate it's own data whenever possible. It's a lot cleaner, for exactly the kind of reasons you're highlighting here.
There are also some subtle advantages, like if you're copying data from a file or socket to the map's data, the data storage exists as soon as the node exists because when the map calls malloc() to allocate the node, it allocates memory for both the key and the data. (AKA map[key].first and map[key].second)
This allows you to use the assignment operator instead of memcpy(), and requires 1 less call to malloc() - the one you make.
IC_CDR CDR, *pThisCDRLeafData; // a large struct{}
while(1 == fread(CDR, sizeof(CDR), 1, fp)) {
if(feof(fp)) {
printf("\nfread() failure in %s at line %i", __FILE__, __LINE__);
}
cdrMap[CDR.iGUID] = CDR; // no need for a malloc() and memcpy() here
pThisCDRLeafData = &cdrMap[CDR.iGUID]; // pointer to tree node's data
A few caveats to be aware of are worth pointing out here.
do NOT call malloc() or new in the line of code that adds the tree node as your call to malloc() will return a pointer BEFORE the map's call to malloc() has allocated a place to hold the return from your malloc().
in Debug mode, expect to have similar problems when trying to free() your memory. Both of these seem like compiler problems to me, but at least in MSVC 2012, they exist and are a serious problem.
give some thought as to where to "anchor" your maps. IE: where they are declared. You don't want them going out of scope by mistake. main{} is always safe.
INT _tmain(INT argc, char* argv[]) {
IC_CDR CDR, *pThisCDRLeafData=NULL;
CDR_MAP cdrMap;
CUST_MAP custMap;
KCI_MAP kciMap;
I've had very good luck, and am very happy having a critical map allocate a structure as it's node data, and having that struct "anchor" a map. While anonymous structs have been abandoned by C++ (a horrible, horrible decision that MUST be reversed), maps that are the 1st struct member work just like anonymous structs. Very slick and clean with zero size-effects. Passing a pointer to the leaf-owned struct, or a copy of the struct by value in a function call, both work very nicely. Highly recommended.
you can trap the return values for .insert to determine if it found an existing node on that key, or created a new one. (see #12 for code) Using the subscript notation doesn't allow this. It might be better to settle on .insert and stick with it, especially because the [] notation doesn't work with multimaps. (it would make no sense to do so, as there isn't "a" key, but a series of keys with the same values in a multimap)
you can, and should, also trap returns for .erase and .empty() (YES, it's annoying that some of these things are functions, and need the () and some, like .erase, don't)
you can get both the key value and the data value for any map node using .first and .second, which all maps, by convention, use to return the key and data respectively
save yourself a HUGE amount of confusion and typing, and use typedefs for your maps, like so.
typedef map<ULLNG, IC_CDR> CDR_MAP;
typedef map<ULLNG, pIC_CDR> CALL_MAP;
typedef struct {
CALL_MAP callMap;
ULNG Knt;
DBL BurnRateSec;
DBL DeciCents;
ULLNG tThen;
DBL OldKCIKey;
} CUST_SUM, *pCUST_SUM;
typedef map<ULNG,CUST_SUM> CUST_MAP, CUST_MAP;
typedef map<DBL,pCUST_SUM> KCI_MAP;
pass references to maps using the typedef and & operator as in
ULNG DestroyCustomer_callMap(CUST_SUM Summary, CDR_MAP& cdrMap, KCI_MAP& kciMap)
use the "auto" variable type for iterators. The compiler will figure out from the type specified in the rest of the for() loop body what kind of map typedef to use. It's so clean it's almost magic!
for(auto itr = Summary.callMap.begin(); itr!= Summary.callMap.end(); ++itr) {
define some manifest constants to make the return from .erase and .empty() more meaningfull.
if(ERASE_SUCCESSFUL == cdrMap.erase (itr->second->iGUID)) {
given that "smart pointers" are really just keeping a reference count, remember you can always keep your own reference count, an probably in a cleaner, and more obvious way. Combining this with #5 and #10 above, you can write some nice clean code like this.
#define Pear(x,y) std::make_pair(x,y) // some macro magic
auto res = pSumStruct->callMap.insert(Pear(pCDR->iGUID,pCDR));
if ( ! res.second ) {
pCDR->RefKnt=2;
} else {
pCDR->RefKnt=1;
pSumStruct->Knt += 1;
}
using a pointer to hang onto a map node which allocates everything for itself, IE: no user pointers pointing to user malloc()ed objects, works well, is potentially more efficient, and and be used to mutate a node's data without side-effects in my experience.
on the same theme, such a pointer can be used very effectively to preserve the state of a node, as in pThisCDRLeafData above. Passing this to a function that mutates/changes that particular node's data is cleaner than passing a reference to the map and the key needed to get back to the node pThisCDRLeafData is pointing to.
iterators are not magic. They are expensive and slow, as you are navigating the map to get values. For a map holding a million values, you can read a node based on a key at about 20 million per second. With iterators it's probably ~ 1000 times as slow.
I think that about covers it for now. Will update if any of this changes or there's additional insights to share. I am especially enjoying using the STL with C code. IE: not a class in sight anywhere. They just don't make sense in the context I'm working in, and it's not an issue. Good luck.