Hello again! In this video, we are going to look at miscellaneous string operations.
We are going to look at the data member function.
You will remember that the string has a pointer to a buffer containing the actual characters.
And when we call the data member function, it returns a pointer to the start of this memory buffer.
You may remember that we had a function c underscore str, which did this. That returned a null terminated
string, and in C++ 11, data() will also return null terminated string.
That might not necessarily be the case in older versions of C++, but in modern versions,
the two do exactly the same thing. And this also works with the vector class as well.
So if you have to work with code written in C. Maybe an operating system API, or some library, or some
old code that you are converting, then you do not have to use arrays and pointers in your C++ code.
You can use string and vector, and then convert the results when you need to interact with C code. For
example, you could use this vector of ints and then, when you have to call this C function, which takes
an array as pointer to int and an element counts, then you can call the data() to get a pointer to the start
of the data, which will be compatible with a C array, and the size member function will return the
number of elements.
So that would be completely compatible with the C code.
So here is that code. I have just written the C-style function that uses an array and a count and prints
out all the elements.
Then we have our vector. And then we pass the results of calling data() and size() as arguments to the C
function.
So there we are, the function points out the elements of the array, and it all works perfectly.
The other string member function I want to talk about is swap().
This also applies to vector as well.
So this will just swap two strings.
We can call it as a member function.
So if we call it on a string and pass another string as argument, then this is going to swap the data
of the two string objects.
So if we have s1 having "Hello" as data and s2, "Goodbye".
Then after the swap operation, s1's data will be "Goodbye" and s2's data
will be
"Hello".
There is also a non-member version of this. So we call swap s1 and s2.
And that will again exchange the data of the two string objects.
So here we are doing this. We are going to do the member function swap and print out the results, and
then do the non-member function swap and print out the results.
So in theory, we should get back to the original strings!
So there we are. We start out with "Hello" and "Goodbye".
Then we have "Goodbye" and "Hello" after doing the swap function with the member function. And then the
non-member function takes us back to the originals.
The non-member version of this function has overloads for all the built-in types and the types in the C++ library.
Obviously, it will not have overloads for your own types unless you provide one.
So what happens in that case? If you call swap and it's not overloaded for that particular object,
then the default is called.
And that just does a naive copy by creating a temporary object.
So it will back up one of the arguments, say the first one and then it will overwrite that argument.
And then it overwrites the second argument with the back up of the first.
And for simple classes where copying is a trivial operation,
that is absolutely fine.
But for something like string, this is going to be rather a slow and inefficient operation.
For starters, each one of these operations will require the data in the string on the right to be copied
into the string on the left.
So that is one processor instruction per character.
In the best case, depending on where it is memory. It could take a lot longer. If the buffer in one
of these strings is not big enough to hold the data from the other object, then it will need to allocate
a new buffer and release the old one.
And memory operations are very slow.
They can often take hundreds of instructions. And in any case, the copy constructor will need to
allocate some memory because it is creating a new object.
So that could quite easily take thousands of processor instructions for what looks like a simple
operation.
And that is time when your processor is doing nothing and it cannot execute any other code from your program.
So that is going to add to the execution time of the program.
So, the string overload does not do that.
It is a bit more clever, it knows what a string is and what a string does.
If you remember what a - if you remember how a string is structured in memory. It has this header
which has the element count and a pointer to the data, and then the actual characters are in a memory
buffer, which the header points to.
So instead of copying data in and out of these buffers and allocating buffers, why not just swap around
the headers?
So s1 will get a header which has the element count for "Goodbye" and a pointer to the data
with "Goodbye".
And s2 ends up with a header which has the element count for "Hello" and points to the data with
"Hello" in it.
So you get the same results, but with much less operations.
All do you do is just swap around these two headers.
So the advantage this is there aren't any memory allocation or release operations, and none of the
actual character data is copied.
The only thing that gets copied is the count and the pointer in the header.
So that's a pointer assignment and an integer assignment for each of these operations.
So that is six assignments in all. And
that is nothing compared to the thousands of instructions that you need with the old way.
OK, so that is it for this video.
I will see you next time, but meanwhile, keep coding!