0% found this document useful (0 votes)
20 views10 pages

Study Notes Unit V

The document provides an overview of C++ stream classes, detailing their hierarchy and functionalities for managing input and output operations. It explains the concept of stream states and error handling, including how to check and clear error flags during file I/O operations. Additionally, it covers file pointers and their manipulation, emphasizing the importance of monitoring stream states to ensure robust program behavior.

Uploaded by

Priyanka
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
20 views10 pages

Study Notes Unit V

The document provides an overview of C++ stream classes, detailing their hierarchy and functionalities for managing input and output operations. It explains the concept of stream states and error handling, including how to check and clear error flags during file I/O operations. Additionally, it covers file pointers and their manipulation, emphasizing the importance of monitoring stream states to ensure robust program behavior.

Uploaded by

Priyanka
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

C++ Streams Classes: The Flow of Data

In C++, the concept of a "stream" represents a flow of data, much like a stream of water. The <iostream> library
provides a hierarchy of classes to manage these streams, allowing you to interact with various input and output devices
(like the console, files, and strings) in a consistent way.
Here's a breakdown of the key stream classes:
1. Basic Stream Classes (Abstract Base Classes):
 std::ios_base: This is the ultimate base class for all input/output stream classes. It defines fundamental
properties and functions that are common to all streams, such as:
 Stream States: It manages the error state of a stream (more on this later).
 Formatting Flags: It controls how data is formatted during input and output (e.g., setting precision
for floating-point numbers, using scientific notation, etc.). These flags can be manipulated using
member functions like flags(), setf(), unsetf().
 Locale: It handles locale-specific formatting (e.g., date and time formats, currency symbols).
 Static Members: It provides static constants and functions related to stream behavior.
 std::ios: This class is derived from std::ios_base and adds type-dependent formatting capabilities. It includes a
pointer to a buffer object (std::streambuf) that is responsible for the actual transfer of data. It also inherits the
stream state and formatting functionalities from std::ios_base.
2. Concrete Stream Classes:
These classes provide specific functionalities for different types of input and output:
 Input Stream Class (Derived from std::ios):
 std::istream: This is the base class for all input streams. It provides member functions for formatted
and unformatted input, such as:
 Formatted Input: operator>> (extraction operator) for reading various data types (integers,
floats, strings, etc.) from the stream. It handles automatic type conversion and skips leading
whitespace by default.
 Unformatted Input: get(), getline(), read() for reading raw characters or blocks of data
without any formatting.
 Other Functions: peek() (examines the next character without extracting it), ignore() (skips
a specified number of characters), putback() (puts the last read character back into the
stream).
 std::ifstream: This class is used for reading data from files. You typically create an object of this class
and associate it with a specific file using its constructor or the open() member function.
 std::istringstream: This class allows you to treat a string as an input stream. You can extract data from
the string using the same input operations as with other input streams.
 std::cin: This is a global object of type std::istream (usually connected to the standard input device,
typically the keyboard).
 Output Stream Class (Derived from std::ios):
 std::ostream: This is the base class for all output streams. It provides member functions for formatted
and unformatted output, such as:
 Formatted Output: operator<< (insertion operator) for writing various data types to the
stream. It applies formatting based on the stream's flags and manipulators.
 Unformatted Output: put() (writes a single character), write() (writes a block of data).
 Other Functions: flush() (forces the stream to write any buffered data to the output device).
 std::ofstream: This class is used for writing data to files. You create an object and associate it with a
file.
 std::ostringstream: This class allows you to build strings by inserting data into an output stream. You
can then retrieve the formatted string using the str() member function.
 std::cout: This is a global object of type std::ostream (usually connected to the standard output device,
typically the console).
 std::cerr: This is another global object of type std::ostream (typically connected to the standard error
output, often the same as std::cout by default, but intended for error messages). It is often unbuffered.
 std::clog: Similar to std::cerr, but it is typically buffered.
 Input/Output Stream Classes (Derived from both std::istream and std::ostream):
 std::iostream: This class inherits from both std::istream and std::ostream, providing capabilities for
both input and output on the same stream.
 std::fstream: This class is used for performing both reading and writing operations on files.
 std::stringstream: This class allows you to perform both input and output operations on strings.
3. Stream Buffers (std::streambuf):
 This is an abstract base class that represents a buffer of characters. It handles the low-level details of
transferring data between the stream and the actual data source or sink (e.g., a file, memory, the console).
 The concrete stream classes (like ifstream, ofstream, stringstream) typically have an associated streambuf
object that manages their interaction with the underlying data. You usually don't interact directly with
streambuf objects.

Stream Errors in C++: Monitoring the Health of Your Streams


During input and output operations, various errors can occur (e.g., trying to read from a non-existent file, encountering
invalid input format). C++ streams have a mechanism to track their error state using a set of status flags. These flags are
part of the std::ios_base class and are inherited by all stream classes.
Stream State Flags:
The stream state is represented by a bitmask of the following flags (defined as enumerators within
std::ios_base::iostate):
 std::ios_base::goodbit (0): This flag indicates that the stream is in a good state and that the last operation
succeeded. No errors have occurred.
 std::ios_base::eofbit (end-of-file bit): This flag is set when an input operation attempts to read past the end of
the input source (e.g., reaching the end of a file). The stream is still considered "good" in the sense that the
operation itself didn't fail due to an error, but no more data is available.
 std::ios_base::failbit (logical error bit): This flag is set when a logical error occurs on the stream, such as:
 A formatted input operation fails to extract the expected data type (e.g., trying to read an integer when
the input is a string).
 A non-fatal error occurs during an input/output operation. When the failbit is set, further operations on
the stream might also fail.
 std::ios_base::badbit (serious error bit): This flag is set when a serious error occurs on the stream, often
related to the underlying buffer or the input/output device. This usually indicates that the stream is in an
unrecoverable state. Examples include:
 A failure during a read or write operation at the system level.
 Loss of integrity of the stream buffer. Once the badbit is set, the stream is generally considered
unusable.
Checking the Stream State:
The stream classes provide member functions to check the current state of a stream:
 bool good() const;: Returns true if no error flags (eofbit, failbit, badbit) are set. This indicates the stream is
healthy and ready for operations.
 bool eof() const;: Returns true if the eofbit is set.
 bool fail() const;: Returns true if either the failbit or the badbit is set. This indicates that a previous operation
failed.
 bool bad() const;: Returns true if the badbit is set.
 std::ios_base::iostate rdstate() const;: Returns the current error state flags as a bitmask. You can check for
specific flags using bitwise operations (e.g., [Link]() & std::ios_base::failbit).
 explicit operator bool() const;: This overloaded operator allows you to directly use a stream object in a boolean
context (e.g., in an if or while condition). A stream evaluates to true if the failbit and badbit are not set (i.e., !
fail()). This is a common way to check if a stream operation was successful.
Example Illustrating Stream Errors:
#include <iostream>
#include <fstream>
#include <string>

int main() {
std::ifstream inputFile("nonexistent_file.txt");
if (!inputFile.is_open()) {
std::cerr << "Error opening file!" << std::endl;
} else {
std::string line;
while (std::getline(inputFile, line)) {
std::cout << "Read line: " << line << std::endl;
}
[Link]();
}
std::cout << "\nTrying to read an integer from standard input:" << std::endl;
int num;
std::cin >> num;
if (std::[Link]()) {
std::cerr << "Error: Invalid input. Expected an integer." << std::endl;
std::[Link](); // Clear the failbit
std::[Link](std::numeric_limits<std::streamsize>::max(), '\n'); // Discard invalid input
} else {
std::cout << "You entered: " << num << std::endl;
}

std::cout << "\nChecking stream states:" << std::endl;


std::cout << "std::[Link](): " << std::[Link]() << std::endl;
std::cout << "std::[Link](): " << std::[Link]() << std::endl;
std::cout << "std::[Link](): " << std::[Link]() << std::endl;
std::cout << "std::[Link](): " << std::[Link]() << std::endl;

return 0;
}

Clearing Error Flags:


Once an error flag (except badbit in some cases) is set, subsequent operations on the stream will typically be no-ops
(they won't do anything). To continue using the stream after an error, you need to clear the error flags using the clear()
member function:stream.
 Calling clear() with no arguments (or with std::ios_base::goodbit) clears all error flags, returning the
stream to a good state.
 You can also explicitly set specific flags by passing a std::ios_base::iostate value. For example,
[Link](std::ios_base::eofbit | std::ios_base::failbit) would set only the eofbit and failbit.
Key Takeaways about Stream Errors:
 Always check the state of your streams after performing input or output operations, especially when dealing
with external resources like files or user input.
 Use the operator bool() overload for a concise way to check if the last operation was successful.
 Use fail() to check for logical errors and bad() for more serious errors.
 The eof() flag is useful for detecting the end of an input source.
 If you want to continue using a stream after a non-fatal error (failbit or eofbit), you need to call clear() to reset
the error state.
 Be cautious when clearing the badbit, as it often indicates a fundamental problem with the stream that might
not be recoverable.
 When handling invalid input, it's often necessary to not only clear the error flags but also to discard the
problematic input from the stream buffer (using ignore()) to prevent it from causing further errors.

Understanding stream classes and how to handle stream errors is crucial for writing robust and reliable C++ programs
that interact with various input and output sources gracefully. By monitoring the stream state and taking appropriate
actions when errors occur, you can prevent unexpected program behavior and provide better error handling to the user.
Alright, let's dive into file pointers and error handling within C++ file I/O using member functions. Here are some study
notes to get you going:
File Pointers (Streams) in C++
In C++, when you work with files, you don't directly manipulate the physical file. Instead, you interact with streams,
which act as an intermediary between your program and the file. These streams maintain internal *file pointers* that
indicate the current position for reading or writing within the file.

Here's a breakdown of the key stream objects and their associated file pointers:

1. std::ofstream (Output File Stream):


 Used for writing data to files.
 Maintains a put pointer. This pointer indicates where the next character will be written in the file.
 When you open a file with std::ofstream, the put pointer is typically positioned at the beginning of the file
(unless you specify std::ios::app for appending).

2. std::ifstream (Input File Stream):


 Used for reading data from files.
 Maintains a get pointer. This pointer indicates the position from where the next character will be read.
 When you open a file with std::ifstream, the get pointer is typically positioned at the beginning of the file.

3. std::fstream (File Stream):


 Used for both reading from and writing to files.
 Maintains both a get pointer and a put pointer, allowing bidirectional operations.

Manipulating File Pointers (Member Functions):

The stream classes (std::istream, std::ostream, and their derived classes) provide member functions to inspect and
modify these internal file pointers:

tellg() (for input streams): Returns the current position of the get pointer as an object of type std::streampos.
tellp() (for output streams): Returns the current position of the put pointer as an object of type std::streampos.
seekg(position) (for input streams): Sets the get pointer to an absolute position within the file. `position` is typically a
value returned by tellg().

std::ifstream inputFile("my_data.txt");
if (inputFile.is_open()) {
[Link](5); // Move the get pointer to the 6th byte (0-based index)
char ch;
[Link](ch);
std::cout << "Character at position 5: " << ch << std::endl;
[Link]();
}

Error Handling in File I/O

File I/O operations can fail for various reasons (e.g., file not found, permission issues, disk full, incorrect data format).
C++ provides mechanisms to check for and handle these errors using the state flags of the stream objects.

Stream State Flags:

Each stream object maintains several state flags that indicate its current status. You can access these flags using member
functions:

good(): Returns `true` if all error flags are clear (no errors occurred).
eof() (End-of-File): Returns `true` if the end of the input file has been reached during a read operation.
fail(): Returns `true` if an error occurred during the last operation, but the stream might still be usable after clearing the
error. This includes logical errors (e.g., trying to read a character into an integer) and formatting errors. `fail()` also
returns `true` if `bad()` is `true`.
bad(): Returns `true` if a serious error occurred during the last operation, and the stream is likely unusable. This often
indicates a problem with the underlying file or device.
rdstate(): Returns the current error state flags as a bitmask of type `std::ios::iostate`. You can compare this value with
predefined constants like `std::ios::goodbit`, `std::ios::eofbit`, `std::ios::failbit`, and `std::ios::badbit`.
Checking for Errors:

It's crucial to check the state of the stream after each I/O operation to ensure it was successful.

#include <iostream>
#include <fstream>
#include <string>

int main() {
std::ifstream inputFile("nonexistent_file.txt");

if (!inputFile.is_open()) {
std::cerr << "Error opening file!" << std::endl;
return 1;
}

std::string line;
while (std::getline(inputFile, line)) {
std::cout << "Read line: " << line << std::endl;
if ([Link]()) {
std::cerr << "Error during reading!" << std::endl;
break;
}
}

if ([Link]()) {
std::cout << "Reached end of file." << std::endl;
} else if ([Link]()) {
std::cerr << "Fatal error encountered while reading." << std::endl;
}

[Link]();
return 0;
}

Clearing Error Flags:

If a non-fatal error (`failbit` is set) occurs, you might be able to recover the stream by clearing the error flags using the
`clear()` member function. This allows subsequent operations on the stream.

#include <iostream>
#include <fstream>

int main() {
std::ifstream inputFile("data_with_errors.txt");
if (inputFile.is_open()) {
int num;
inputFile >> num;
if ([Link]()) {
std::cerr << "Error reading an integer. Clearing error flags." << std::endl;
[Link](); // Clear the failbit
std::string remainingData;
inputFile >> remainingData;
std::cout << "Remaining data: " << remainingData << std::endl;
} else {
std::cout << "Successfully read integer: " << num << std::endl;
}
[Link]();
} else {
std::cerr << "Error opening file." << std::endl;
}
return 0;
}
Best Practices for Error Handling:

 Always check if the file was opened successfully using is_open() or by directly checking the truthiness of the
stream object (if (!inputFile)).
 Check the stream state after each significant I/O operation to detect errors early.
 Use eof() to specifically check for the end of the file during read loops.
 Differentiate between fail() and bad() to understand the severity of the error. bad() usually indicates a more
critical problem.
 Consider using exceptions for more robust error handling in larger applications. You can configure streams to
throw exceptions on certain error conditions using the exceptions() member function.

std::ifstream inputFile("[Link]");
[Link](std::ios::failbit | std::ios::badbit);
try {
std::string line;
std::getline(inputFile, line);
std::cout << "Read line: " << line << std::endl;
[Link]();
} catch (const std::ios_base::failure& e) {
std::cerr << "Exception caught: " << [Link]() << std::endl;
// Handle the exception
}

By understanding file pointers and implementing proper error handling using the member functions of the stream
classes, you can write more robust and reliable C++ programs that interact with files. Remember to always close your
file streams when you are finished with them to release system resources.

Command Line Arguments


What are Command-Line Arguments?

When you run an executable program from your terminal or command prompt, you can often provide additional pieces
of information right after the program's name. These extra bits of data are called command-line arguments. They allow
you to customize the behavior of your program without needing to recompile it.

How C++ Handles Command-Line Arguments

In C++, the main function is the entry point of your program. It can optionally accept two arguments that provide access
to the command-line inputs:

int main(int argc, char *argv[]) {


// Your program logic here
return 0;
}
Example:

#include <iostream>

int main(int argc, char *argv[]) {


std::cout << "Number of arguments: " << argc << std::endl;
std::cout << "Program name: " << argv[0] << std::endl;

if (argc > 1) {
std::cout << "First argument: " << argv[1] << std::endl;
}

if (argc > 2) {
std::cout << "Second argument: " << argv[2] << std::endl;
}

return 0;
}
If you compile and run this program with the command:
Bash
g++ command_args.cpp -o command_args
./command_args my_input data
The output will be:
Number of arguments: 3
Program name: ./command_args
First argument: my_input
Second argument: data

Let's break down these arguments:

1. int argc (Argument Count):

 This is an integer that represents the number of command-line arguments passed to your program,
including the program's name itself.1

 So, if you run your program like this: $ ./myprogram hello world 123, then argc will be 4.
2. char *argv[] (Argument Vector):

 This is an array of C-style strings (character pointers). Each element of this array points to a
command-line argument.

 argv[0] always contains the name of the program as it was executed (e.g., ./myprogram).
 argv[1] will contain the first argument after the program name (e.g., "hello").
 argv[2] will contain the second argument (e.g., "world").
 And so on... argv[argc - 1] will contain the last argument.
 argv is null-terminated, meaning argv[argc] is guaranteed to be nullptr (or NULL in older C++).
Common Uses of Command-Line Arguments

 Providing input files: Instead of hardcoding filenames, you can pass them as arguments.
 Setting program options/flags: You can use arguments like -v for verbose output or -o [Link] to specify an
output file.

 Passing configuration parameters: You can provide values for settings like port numbers or database names.
 Scripting and automation: Command-line arguments make your C++ programs more flexible for use in
scripts.

Important Considerations
 String Conversion: Command-line arguments are always passed as strings. If you need to use them as
numbers (integers, floats, etc.), you'll need to explicitly convert them using functions like std::stoi, std::stod,
etc. Be sure to handle potential exceptions if the input string is not a valid number.

 Error Handling: Always check the value of argc before accessing elements of argv to avoid going out of
bounds and causing crashes.

 Argument Parsing Libraries: For more complex command-line options (like short and long flags, arguments
with values, etc.), consider using dedicated libraries like getopt.h (for POSIX-style options) or more advanced
third-party libraries (e.g., Boost.Program_options). These libraries can significantly simplify the process of
parsing and validating command-line input.

In Summary

Command-line arguments provide a powerful way to interact with your C++ programs at runtime, making them more
versatile and adaptable. Understanding argc and argv is fundamental for accepting and processing this external input.
Remember to handle the string nature of the arguments and implement proper error checking.

Function Templates
 What they are: Blueprints for creating functions that can operate on different data types without being
rewritten for each type. They use template parameters to represent these generic types.

 Syntax:
template <typename T>
T myFunction(T a, T b) {
// Function body using type T
return a + b;
}
or

template <class U> // 'class' and 'typename' are often interchangeable here
U anotherFunction(U value) {
// ...
}
 How they work: The compiler instantiates a specific function based on the data types used when the template
function is called. This happens at compile time.

 Benefits: Code reusability, reduced code duplication, type safety (the compiler checks if the operations are
valid for the used types).

Class Templates

 What they are: Blueprints for creating classes that can work with different data types. Similar to function
templates, they use template parameters for generic types within the class definition.

 Syntax:
C++

template <typename T>


class MyClass {
private:
T data;
public:
MyClass(T value) : data(value) {}
T getData() const { return data; }
void setData(T newValue) { data = newValue; }
// ... other members using type T
};
 Instantiation: You create specific class types by providing the actual type for the template parameter when
declaring an object:

C++

MyClass<int> intObject(10);
MyClass<double> doubleObject(3.14);
 Benefits: Code reusability for data structures and algorithms, type safety, flexibility in handling different data
types.

Exceptions
 What they are: A mechanism in C++ to handle runtime errors or unusual conditions that disrupt the normal
flow of a program.

 Key Components:
 throw: A statement used to signal that an exception has occurred. It creates and throws an exception
object.

 try block: A block of code where exceptions might occur.


 catch block: A block of code that handles a specific type of exception thrown within the preceding try
block.

 Basic Structure:

try {
// Code that might throw an exception
if (/* error condition */) {
throw std::runtime_error("Something went wrong!");
}
} catch (const std::runtime_error& error) {
// Handle the std::runtime_error exception
std::cerr << "Error: " << [Link]() << std::endl;
} catch (...) {
// Catch any other type of exception (catch-all handler)
std::cerr << "An unexpected error occurred." << std::endl;
}
 Exception Hierarchy: C++ has a standard library of exception classes (e.g., std::exception, std::runtime_error,
std::logic_error, etc.) arranged in an inheritance hierarchy. You can also define your own custom exception
classes.

Containers
 What they are: Objects that hold collections of other objects. The C++ Standard Template Library (STL)
provides various container classes to manage data in different ways.

 Common Container Types:


 Sequence Containers: Store elements in a linear sequence. Examples:
 std::vector: Dynamically resizable array.
 std::deque: Double-ended queue (efficient insertions/deletions at both ends).
 std::list: Doubly-linked list (efficient insertions/deletions anywhere).
 std::forward_list: Singly-linked list (minimal overhead).
 std::array: Fixed-size array.
 Associative Containers: Store elements in a sorted manner, allowing efficient retrieval based on
keys. Examples:

 std::set: Stores unique elements, sorted.


 std::multiset: Stores elements, sorted (duplicates allowed).
 std::map: Stores key-value pairs, sorted by key (unique keys).
 std::multimap: Stores key-value pairs, sorted by key (duplicate keys allowed).
 Unordered Containers (C++11 onwards): Provide (on average) constant-time complexity for
insertion, deletion, and lookup, but elements are not stored in any particular order. Examples:

 std::unordered_set: Stores unique elements.


 std::unordered_multiset: Stores elements (duplicates allowed).
 std::unordered_map: Stores key-value pairs (unique keys).
 std::unordered_multimap: Stores key-value pairs (duplicate keys allowed).
 Key Features: Containers manage memory allocation, provide methods for element access, insertion, deletion,
and iteration.

Exception Handling in C++


 Purpose: To write robust and fault-tolerant programs by gracefully handling unexpected events that occur
during runtime.

 Benefits:
 Separation of Error Handling Code: Keeps the main logic of the program cleaner by isolating error
handling in catch blocks.

 Improved Program Reliability: Prevents program crashes by providing a way to recover from
errors.

 Passing Error Information: Exception objects can carry information about the error that occurred,
allowing catch blocks to handle it appropriately.

 Best Practices:
 Throw by value, catch by reference (const): Avoids slicing and unnecessary copying of exception
objects.

 Be specific with catch blocks: Catch the specific exception types you know how to handle. Use a
catch-all (catch(...)) as a last resort.

 Resource Acquisition Is Initialization (RAII): Use objects (like smart pointers) to manage resources
so that they are automatically released even if an exception is thrown.

 Don't overuse exceptions for normal control flow: Exceptions should be reserved for truly
exceptional circumstances.

 Provide informative exception messages: Make it easier to understand and debug errors.

You might also like