What happens if this function is exported as an ordinal function from a DLL (not an inlined piece of code inside a header) and you call it from an EXE?
It works most of the time. When it doesn’t, it corrupts your heap and causes a spectacular mess.
In Windows you must free memory with the same allocator that allocated it. However, your EXE may not share the same allocator as the DLL. Perhaps the two modules are linked against different versions of libc, or perhaps one of the modules is using a static version of libc. If your EXE and DLL do not share an allocator and if AppendChar() resizes the string s, you will almost certainly cause a heap corruption.
The STL has a pointer-to-member function adapter called std::mem_fun() which almost gets us there. Unfortunately, it doesn’t quite meet our needs because it requires us to pass a pointer to an instance of C, as in:
template<typenameT1,typenameT2>structmy_pair{typedefT1first_type;typedefT2second_type;my_pair():first(T1()),second(T2()){}my_pair(constT1&v1,constT2&v2):first(v1),second(v2){}T1first;T2second;};template<typenameT1,typenameT2>inlinebooloperator<(constmy_pair<T1,T2>&x,constmy_pair<T1,T2>&y){return(x.first<y.first||x.second<y.second);}voidf(){typedefmy_pair<...,...>key_type;typedef...value_type;typedefstd::map<key_type,value_type>map_type;map_typemap;// Use map
}
Answer: my_pair cannot be used as a key for a STL map because the operator< violates the rule of strict weak ordering. More specifically, the operator is not antisymmetric. Consider the following:
I recently wrote a piece of code that looked something like the following:
staticconstintNUM_TOTAL_VALUES=...;typedef...T;// Create vec and reserve NUM_TOTAL_VALUES spaces for later insertion
std::vector<T>vec(NUM_TOTAL_VALUES);// Insert values into vec
for(inti=0;i!=NUM_TOTAL_VALUES;++i)vec.push_back(...);// vec should now have NUM_TOTAL_VALUES values in it (but doesn't!)
What’s wrong with this code?
The constructor vector(size_type _Count); does more than just allocate enough space to store _Count items — it also inserts _Count (default constructed) items into the vector. To reserve space without actually inserting values, use reserve():
If my experience is typical, this is a very common construct:
ReturnTypeFunction(conststd::vector<T>&container){typedefstd::vector<T>::const_iteratoriterator_t;for(iterator_titer=container.begin();iter!=container.end();++iter){// Work with *iter
}}
The problem with this construct is that you have forced a container choice upon the user of your function. Slightly better, and basically your only choice when interoping with C, is this:
ReturnTypeFunction(T*array,intnumItems){for(inti=0;i<numItems;++i){// Work with array[numItems]
}// Or perhaps:
// for (T* pT = array; pT != array + numItems; ++pT) {
// Work with *pT
// }
}
With the above construct you can pass in any container which uses contiguous storage, such as an array or a std::vector (yes, std::vectorsare guaranteed to store the data contiguously). Passing a std::vector to the above function looks like:
I’ve seen the following STL construct countless times:
std::vector<T>container;for(inti=0;i<container.size();++i){// Work with container[i]
}
Unless otherwise necessary, it is better to use an STL iterator because it enables you to more easily change the underlying container. You can isolate the code changes required to one line by using typedef, as in:
typedefstd::vector<T>container_t;container_tcontainer;// Or ::const_iterator as necessary
for(container_t::iteratoriter=container.begin();iter!=container.end();++iter){// Work with *iter
}
Note that I wrote iter != container.end() as opposed to iter < container.end(). The former only requires an input iterator, while the latter requires a random access iterator—a more complicated iterator type supported by fewer STL containers.