C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
198: String Streams with stringstream
I've seen this exact bug more times than I can count. You're trying to parse a list of items—maybe some comma-separated values or a log file—and you decide to use a std::stringstream because it makes extracting different data types (like ints and strings) a breeze. Everything works perfectly for the first item, but then the program just... stops. It skips the rest of the data without throwing an error.
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
void parseData(const std::vector<std::string>& lines) {
std::stringstream ss;
for (const auto& line : lines) {
ss << line;
int id;
std::string name;
// We expect "ID Name" (e.g., "101 Alice")
if (ss >> id >> name) {
std::cout < "Parsed: " < id < " - " < name < "\n";
}
}
}
int main() {
std::vector<std::string> data = {"101 Alice", "102 Bob", "103 Charlie"};
parseData(data);
return 0;
}
The EOF Trap
If you run this, you'll notice it prints "Parsed: 101 - Alice" and then goes silent. You might think the loop is broken, but the loop is running fine. The problem is the stringstream object.
When you extract "Alice" from the first line, the stream reaches the end of that string. This sets an internal state flag called eofbit (End Of File). Once that flag is set, the stream enters a "fail" state. Even though we use ss << line to push new data into the buffer for the second iteration, the eofbit is still there. C++ won't let you extract any more data from a stream that thinks it has already hit the end of the file.
Resetting the Stream State
To fix this, you have to do two things: clear the error flags and empty the internal buffer. If you just clear the flags, the old data ("101 Alice") is still sitting in the buffer, and your new data gets appended to the end of it, which is rarely what you want.
Here is the corrected approach:
void parseData(const std::vector<std::string>& lines) {
std::stringstream ss;
for (const auto& line : lines) {
// 1. Clear the error flags (like eofbit)
ss.clear();
// 2. Replace the internal buffer with the new string
ss.str(line);
int id;
std::string name;
if (ss >> id >> name) {
std::cout < "Parsed: " < id < " - " < name < "\n";
}
}
}
By calling ss.clear(), we tell the stream, "Forget that you hit the end of the file; we're starting over." By calling ss.str(line), we aren't appending to the buffer; we are completely replacing the contents of the stream with the new line.
When to use stringstream over to_string
You might be wondering why we bother with stringstream when we have std::to_string() or std::stoi(). The real power of string streams is formatting and type-mixing. If you need to build a complex string that includes hex values, precision-limited floats, and integers all in one go, stringstream is your best friend.
I personally use them whenever I need to "serialize" a custom object into a string. Because stringstream inherits from the same base classes as std::cin and std::cout, you can use all the manipulators you already know, like std::setprecision or std::setw, to make your strings look exactly right before you call .str() to get the final result.
Handling Delimiters with getline
The >> operator is great for whitespace-separated data, but real-world data is often comma-separated (CSV). For that, you can combine stringstream with std::getline. Remember that getline takes a third argument—the delimiter.
std::string csvLine = "Apple,1.50,10";
std::stringstream ss(csvLine);
std::string segment;
while (std::getline(ss, segment, ',')) {
std::cout < "Field: " < segment < "\n";
}
This is a pattern I use constantly for simple configuration files. It's cleaner than writing a manual character-loop and much safer than using strtok from the old C days.
📋 Practical Task
Build a Product Catalog Formatter
Your task is to create a program that takes "raw" product data strings and converts them into a formatted, human-readable catalog entry.
Requirements:
- Create a
struct Productwith astd::string name,double price, andint quantity. - Write a function
Product parseProduct(std::string rawData)that takes a comma-separated string (e.g.,"Gaming Mouse,49.99,120") and uses astd::stringstreamto parse it into aProductobject. - Write a function
std::string formatProduct(Product p)that uses astd::stringstreamto return a string formatted exactly like this:"ITEM: Gaming Mouse | PRICE: $49.99 | QTY: 120". (Ensure the price always shows two decimal places usingstd::fixedandstd::setprecision(2)). - In
main, test this with a vector of at least three different raw product strings and print the formatted results.
There are no comments for now.