UPI Study › Courses › C++ Programming › Free lessons › Lesson 7.4 Free with a free account
The String Class Toolkit
C++ Programming · Chapter 7: Text and Applied CollectionsSection 7.4 · lesson 46 of 84video coming soon
← Assembling and Editing String ContentNext lesson: Presenting Text Precisely →
In this lesson
Properties, methods, and practical usage.
- Explain value semantics: copying, assigning, comparing
- Tell size from capacity, and know when storage moves
- Read iterator code: what begin() and end() mean
- Pass and return strings without needless copies
Transcript
Everything said in the video, section by section (1,435 words). Read along, or search it.
Big Picture
What Kind of Thing Is a String
You've been using std::string operation by operation. This lesson steps back and asks what kind of thing it is. Almost everything about how it behaves, what it costs, and how it should be passed around follows from a single fact: it's an object that owns its own storage, and behaves like a value.
Core Concept
Value Semantics Versus Raw Pointers
A std::string holds its own characters. It isn't a pointer to text living elsewhere. This is called value semantics: a string behaves the way int does, rather than the way a raw array does. A holds Bhopal. B equals a makes b an independent copy. Setting b to Indore changes b only. A is still Bhopal. And comparing a with Bhopal compares the text, not addresses. Now two char pointers, aimed at two separate arrays that both spell Bhopal. P equals equals q asks about the arrows, not the text, and says no. After a string copy, the two strings share nothing. With pointers, it's one set of characters with two names, or two sets that merely look alike.
Benefits and Cost
What Value Semantics Buys You
Here's what value semantics buys you. A copy of a string is independent. With an array, assignment isn't allowed at all, and with a pointer, it copies the arrow, not the text. Equals-equals is true when the text matches, and less-than gives dictionary order, rather than comparing addresses. Passed by value, a function gets its own copy. And returning a string from a function is safe. Returning a local array's address is a serious fault. The trade is that copies are real. Assigning or passing a long string by value copies every character. That isn't a reason to avoid strings. It's the reason for const references, coming shortly.
Sub-Topic
Size Versus Capacity in Growth
Two different numbers describe how much room a string is using. Size is how many characters it currently holds. Capacity is how many it could hold before it must find somewhere bigger. Capacity is always at least as large as size, and usually larger. Watch a real string grow, one character at a time. It starts empty, with room to spare. Whenever the capacity changes, the program prints the size at that moment. Append one character past capacity, and a larger block is obtained, every character is moved into it, and the old block is released. The exact numbers depend on the library. When you already know roughly how long the result will be, reserve asks for that capacity up front, and removes the moves altogether.
Common Mistake
Reallocation Invalidates Held Positions
Reallocation isn't free, but it's rarer than it looks. Capacity grows by a multiplying factor, rather than by one, so a move happens only occasionally, and the average cost per character stays small. But there's a consequence that catches people. When a string reallocates, its characters physically move. Anything that was pointing into the old block, a pointer, a reference to a character, or an iterator, now refers to memory that's been released. Using it afterward is undefined behavior. It might print the right letter, or garbage, or crash, and the symptom often appears far from the cause. So the rule is simple. Don't hold on to a position inside a string across any operation that might change its length.
Comparison
Brackets Versus At for Indexing
Square brackets and at both reach a character by index. They differ over exactly one thing: what happens when the index is wrong. Square brackets don't check. They read or write whatever is there, and the behavior is undefined. At checks, and throws an out of range exception, which can be caught and reported. The check costs one comparison per access. The sensible default is brackets inside loops you've written and bounded yourself, and at whenever the index has any other origin: input, a calculation, or a file. One precise detail. The position equal to the size is defined, and yields the null character. That's how a string can hand its contents to C-style interfaces. At, with the same index, throws, as it should.
Definition
Iterators and the Half-Open Range
An iterator is a position within a sequence. Begin gives the position of the first character. End gives the position one past the last, not the last character itself. Together they mark a half-open range: the first character, and one step past the final one. End is a stopping marker, and it's never dereferenced. It's the same idea as indexes running from zero to size minus one. That's why an iterator loop stops on not-equal to end, rather than on less-than-or-equal to something. So there are three ways of walking a string, and they do the same work. An index loop, when the position number is needed. An iterator loop, when working with library operations that take positions. And the range-based loop, for everyday reading: the shortest, the clearest, and it can't go out of range. Iterators aren't a string idea at all. A vector has begin and end, meaning exactly the same thing, and so does every other standard container. Learning the convention once buys you the whole library.
Worked Example
Choosing How to Pass Strings
Because a string owns its characters, passing one by value copies all of them. For a parameter the function only reads, that copy is pure waste. The fix is a reference marked const, which gives access without a copy, and without permission to modify. Report takes a const reference: it reads only. Shout takes a plain reference, because it modifies the caller's string. Tag takes its own copy by value, which is honest only if it needs one. And join parts returns a new string by value. Returning by value is correct, and efficient in practice. Run it to see each effect. Report prints the name. Shout changes the caller's string, adding an exclamation mark. Tag's star lands only on its own copy, so n never gets one.
Absolute Rule
Never Return a Local Reference
One rule here is absolute. Never return a reference to a local string. A local string ceases to exist when the function ends. Returning a reference to one hands back a reference to something that's gone, and the caller reads memory that's been reused. The compiler can spot this one and warns. Return by value instead. It's safe, and it isn't the performance problem it looks like.
Application
Strings Inside Containers and Loops
Strings are ordinary values, so they sit inside containers exactly as numbers do. An array of seven strings holds the days of the week. A vector of strings grows with push back, adding Rahul, then Priya. And notice the parameter form appearing again, in the range-based loop. Writing for string n in names copies every string once per pass. Writing const string reference doesn't. The same reasoning that governs function parameters governs loop variables, because it's the same question: does this need its own copy?
Reference List
Member Functions Grouped by Purpose
Here's a reference, consolidated for lookup, rather than for reading through. Size and storage: size, length, empty, capacity, reserve, and clear. Access: brackets, at, front, back, begin and end. Searching: find, r find, and find first of. Extracting and building: sub S T R, plus, append, and push back. Modifying: insert, erase, replace, and resize. And comparing and converting: the relational operators, compare, and c str, for C interfaces. Notice how much of it repeats across the library. Size, empty, clear, push back, begin and end mean the same things on a vector, deliberately so. The library is built on a small number of conventions, applied consistently, which is why the second container you learn takes far less effort than the first.
Decision Guide
When to Use std::string
So which representation, and when? For any new code holding or building text, use std::string. That's the default, with no realistic exception at this stage. The same goes for text whose length isn't known in advance, and for text that must be compared, sorted, or stored in a container. Even when calling a C library, keep the string, and hand over c str at the boundary. And when reading older code that predates it, recognize the char array, and know the terminator's role. Don't convert working code without a reason.
Quick Check
Counting Moves for 1,000 Appends
Quick check. A loop appends 1,000 characters to an empty string, one at a time. Using the growth you saw earlier, roughly how many times do the characters move? And what one call, made first, would avoid every move? Pause and think. About six. Capacity roughly doubles each time, so on this library it passes a thousand after six moves. And calling reserve(1000) first gets all the room up front, so the characters never move at all.
Key Takeaways
Four Rules to Remember
To summarize. Copies of a string are independent, and equals-equals compares the text. Reallocation moves the characters, so never hold a position across a change of length. Use square brackets in loops you've bounded yourself, and at otherwise. And declare read-only string parameters as const references.
About C++ Programming at UPI Study
C++ Programming (Computer Science 242) is a self-paced online course of 84 video lessons in 11 chapters, from your first program to decisions, loops, arrays, functions, classes, files, pointers and inheritance. It carries a NCCRS credit recommendation for 3 semester credits.
Every lesson transcript is free on pages like this one, and the videos are free with a free UPI Study account. Enrolling adds a practice quiz after each lesson, the graded work and final exam that earn the credit, lifetime access, and an official transcript on completion. UPI Study has helped over 130,000 students with college credits. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Enroll now → Course details Download the syllabus Every course with PRO →
Why take it here
Why students take C++ Programming with UPI Study
Where the credit goes
Universities that work with NCCRS
C++ Programming carries a NCCRS credit recommendation. These universities work with NCCRS; some are UPI Study's signed partners. ACE and NCCRS have over 2,100 cooperating colleges that will consider accepting credits; the final decision is with the universities.
Thomas Edison State UniversitySigned partner
University of the PeopleSigned partner
Charter Oak State CollegeSigned partner
Strayer UniversitySigned partner
Columbia Southern UniversitySigned partner
Indiana TechSigned partner
Penn StateWorks with NCCRS
Southern New Hampshire UniversityWorks with NCCRS
SUNYWorks with NCCRS
+many more cooperating universitiesFind my college →Find my college → Not listed? Ask Athena in the corner of this page, or book a 15-minute call.
FAQ
Questions students ask us
About The String Class Toolkit
What is value semantics for std::string, and how does it affect copying and comparing?
What is the difference between size and capacity of a C++ string?
What do begin() and end() mean when reading iterator code for a string?
How should I pass and return strings in C++ without making needless copies?
About the C++ Programming course
How many college credits is C++ Programming?
How much does C++ Programming cost and what is included?
Which universities accept UPI Study credits?
How long does C++ Programming take?
How are the exams done?
How do my credits reach my college?
Ready for the full course? Earn 3 credits in C++ Programming.
84 video lessons, a quiz after each one, and the graded work that earns the credit. Recommended for credit by NCCRS.
3 credits · NCCRSEnroll →