Item 16: How to pass the data of Vector and String to the traditional API function
Because the C language has been standardized in 1998, C is not worried when trying to drive the programmer from the array to the vector. The same situation also occurs during the process of transferring from a char * pointer to the String object. There is a good reason to do these transformations, such as eliminating common programming errors (Item 13), and has the opportunity to obtain all powerful power of STL generic algorithms (see, for example, Item 31).
However, trouble is still, and the most common one is that the traditional C style API function that has existed is an array and char * pointer instead of Vector and String objects. Such API functions will still have a long time. If we want to use STL efficiently, you must share peacefully.
Fortunately, this is easy. If you have a Vector object V, you need to get a pointer to the data in V, so that it can be treated as an array, as long as & v [0] is available. For String object S, the corresponding syntax is very simple S.C_STR (). But only from above. If advertising is often indicated, there are several restrictions. .
Give a given one
Vector
Expression V [0] Produces a reference to the first element of the vector, so & v [0] is a pointer to that first element. The element in the vector is limited to the C standard to store in continuous memory, just like an array, so if we pass V to the C-style API function in such a form
Void Dosomething (const INT * PINTS, SIZE_T NUMINTS);
We can do this:
DOSMETHING (& V [0], v.size ());
Maybe. Probably. The only problem is that if V is empty. If this is, v.size () is 0, and & V [0] attempts to generate a pointer to something that does not exist at all. This is not a good thing. The result is not defined. One more secure method is this:
IF (! v.empty ()) {
DOSMETHING (& V [0], v.size ());
}
If you can't walk, you may encounter some of the characters of some half bottles, they will tell you that you can use v.begin () instead & v [0], because (these hate guys will tell you) Begin () Back Point to the Iterator inside the vector, and for the vector, its Iterators is actually a pointer. That is often correct, but if Item 50 is said, it is not always, you should not depend here. The return type of Begin is Iterator, not a pointer, and should never use begin when you need a pointer to the internal data of the Vector. If you decide to type V. Segin () based on some reason, type & * v.begin (), because this will generate the same pointer as the & v [0], although it makes you have more keystrokes and Let the code read more embarrassment. In confession, if you are being told you to use V. Segin () instead of people around & v [0], you should re-consider your social circle.
Similar to the method of getting a pointer to internal data from the Vector, it is unreliable for String because the data in the string is not committed to the continuous memory, and the internal representation of String does not promise At the end of an empty character. This explains the reason for the String member function c_str (), which returns a value of the C style design pointer, pointing to the value of String (Which Returns A Poin Designed for C). We can pass a String object S to this function, Void Dosomething (const char * pstring);
Just like this:
DOSMETHING (S.C_STR ());
Even the length of the string is 0, it works. In that case, c_str () will return a pointer to the end of the end. Even when there is a end compact in the string, it works. However, if this is true, DOSMETHING is likely to interpret the first ender as the end of the string. String objects do not care whether end confession is accommodated, but based on char *'s C style API function is intended.
Look at the declaration of DOSMETHING ():
Void Dosomething (const INT * PINTS, SIZE_T NUMINTS);
Void Dosomething (const char * pstring);
In both forms, the pointer is passed to a pointer to the const. The data of Vector and String is transmitted to only readings without modifying their API functions. It is the safest thing to do so far. For String, this is also the only thing that can be done because there is no promise that the pointer generated by c_str () refers to the internal representation of String data; it can return a pointer to a non-modified copy of the data, this copy meets the C-style API Function to format requirements. (If this intimidation makes your cold hair, please also be wrapping, because it may not be settled. I have not heard which runtime current is used to use this freedin.)
For Vector, there are more flexibility. If you pass V to a C style API function that modifies its element, it is no problem, but the function being called must never try to change the number of elements in the vector. For example, it must not be tried to "create" new elements on the capacity that VECTOR has not used. If you do this, V will become inconsistent within the internal state, because it doesn't know your right size (size). v.size () will get an incorrect result. Also, if the function being called is attempting to add data on a VECTOR of a size and capacity (see iTEM 14), there will be a catastrophic event. I don't even want to imagine it at all. It's too terrible.
Do you notice that I use the word "typical" in front? You of course noticed it. Some vectors have some additional restrictions on their data. You must ensure that these additional restrictions continue to be met. For example, ITEM 23 explains the sorted VECTOR is often used to implement an associated container, but it is important to remain sorted by these vectors. If you pass a sorted Vector to an API function that may modify its data, you need to pay attention to the case where the vector is no longer sorted after the return is returned.
If you want to initialize a vector with an element returned with a C style API function, you can use the VECTOR and the inner compatibility to pass the space of the battery to the API function by using the space stored in the storage of VECOTR:
// c API: This function takes a pointer to an array of at motraysize // Doubles and Writes Data to it. It Returns the number of doubles write,
// Which is never more Than maxnumdoubles.
SIZE_T FILLARRAY (double * parray, size_t arraysize);
Vector
// size is maxnumdoubles
vd.resize (Fillarray (& VD [0], vd.size ())); // Have Fillarray Write Data
// INTO VD, THEN RESIZE VD
// to the number of
// Elements Fillarray Wrote
This trick can only work in Vector, because only the vector commitment is the same inner memory distribution as the array. However, if you want to initialize the String object with data from the C style API function, you can do it simple enough. Just let the API function put the data into a vector
// c API: this function takes a pointer to an array of at MOST ARRAYSIZE
// Chars and Writes Data to It. It returns the number of chars written,
// Which is never more Than maxnumchars.
SIZE_T FILLSTRING (Char * PARRAY, SIZE_T ARRAYSIZE);
Vector
// size is maxnumchars
Size_t charswritten = FillString (& VC [0], vc.size ()); // Have FillString Write
// INTO VC
String s (vc.begin (), vc.begin () charswritten; // Copy Data from VC to S
// via Range Constructor
// (See Item 5)
In fact, this idea is always valid: let the C style API function put the data into a vector and copy it to the STL container you actually want.
SIZE_T FILLARRAY (double * parray, size_t arraysize); // AS Above
Vector
Vd.resize (Fillarray (& VD [0], vd.size ());
Deque
// deve
List
SET
Void Dosomething (const INT * PINTS, SIZE_T NUMINTS); // C API (from Above)
Set
... // Data To Pass To API
Vector
// a Vector
IF (! v.empty ()) DOSMETHING (& V [0], v.size ()); // Pass the data to
// the API
You can also copy data into an array, then pass the array to the C style API, but why do you want to do this? Unless you know the size of the container in the compile period, you have to assign a dynamic array, and Item 13 explains why you should always use the versions of the dynamic assignment.