Unit 3: Data Files, Constructors and Destructors
I. Orientation: Persistent Data and Object Lifetime
C++ file handling stores data outside program memory, while constructors and destructors control an object's valid lifetime. File streams connect a program to external data; manager functions establish and release the resources owned by objects.
- Persistence: Variables normally disappear when a program ends, but data written to a file remains available for later execution.
- Stream model: A stream is a flow of bytes between a program and a source or destination. C++ provides file streams through the
<fstream>header. - File positions: Streams maintain a get pointer for reading and a put pointer for writing.
- Text and binary formats: Text files store formatted characters; binary files store byte representations without textual conversion.
- Object lifetime: An object's lifetime begins after construction succeeds and ends when its destructor finishes.
- RAII convention: Resource Acquisition Is Initialization ties resources such as files or memory to object lifetime, enabling automatic cleanup.
- Manager functions: Constructors initialize objects, while destructors release resources and perform final cleanup.
II. File Stream Fundamentals — Connecting Programs to Files
File stream objects provide controlled communication between a C++ program and files stored on secondary storage.
A. Opening and closing files
Opening associates a stream object with a named file, and closing ends that association.
- Stream classes:
ifstream: Reads from files.ofstream: Writes to files.fstream: Supports both reading and writing.
- Constructor opening: A filename and optional mode can be supplied when the stream is created.
- Explicit opening: The
open()member allows a previously created stream to be connected later. - Status check:
is_open()confirms association, whileif (!file)detects an opening or stream failure. - Closing:
close()flushes buffered output and releases the operating-system file handle. Destruction also closes an open stream automatically.
#include <fstream>
using namespace std;
ifstream input("marks.txt");
if (!input.is_open()) {
return 1;
}
input.close();B. File modes
File modes specify the permitted operation and the treatment of existing content.
ios::in: Opens a file for input.ios::out: Opens for output; withofstream, existing content is normally truncated unless combined with modes such asapp.ios::app: Forces every write to the end of the file.ios::ate: Opens the file and initially places the position at the end, but later seeking is permitted.ios::trunc: Discards existing contents when the file opens.ios::binary: Prevents text-mode translations and processes raw bytes.- Combined modes: The bitwise OR operator joins compatible flags.
fstream file("records.dat",
ios::in | ios::out | ios::binary);C. File stream functions
File stream functions manage data transfer, positions, and stream state.
- Character operations:
get(ch)reads one character;put(ch)writes one character. - Line operation:
getline(stream, text)reads through a delimiter, normally newline, and removes that delimiter. - Binary operations:
read()andwrite()transfer a specified number of bytes. - Position operations:
seekg()andtellg()control or report the get position;seekp()andtellp()handle the put position. - State operations:
good(): No error flags are set.eof(): End-of-file has been encountered by an attempted read.fail(): A formatting or operational failure occurred.bad(): A serious input/output error occurred.clear(): Resets state flags, often before seeking after EOF.
D. Reading and writing files
Formatted file operations use extraction and insertion operators similarly to console input and output.
- Writing:
<<converts values such as42or3.5into character sequences. - Reading:
>>converts file characters into a value of the requested type and normally skips leading whitespace. - Whole lines:
getline()preserves spaces within text such as"Ada Lovelace". - Correct loop: The read operation itself should control iteration;
while (!file.eof())can process stale data after a failed read. - Concrete example:
ofstream out("marks.txt");
out << 101 << ' ' << 86.5 << '\n';
out.close();
ifstream in("marks.txt");
int roll;
double mark;
while (in >> roll >> mark) {
// Use one successfully read record.
}III. File Processing Methods — Locating and Representing Records
File-processing strategy determines whether records are visited in order or reached directly through calculated positions.
A. Sequential access and random access file processing
Sequential access processes records in storage order, whereas random access moves directly to a selected byte position.
- Sequential access:
- Principle: Each record is read after the preceding record, usually with
while (file >> value). - Strength: It suits logs, reports, and variable-length text records.
- Limitation: Reaching record 1,000 generally requires processing records 1 through 999 first.
- Principle: Each record is read after the preceding record, usually with
- Random access:
- Principle:
seekg()orseekp()repositions a stream relative toios::beg,ios::cur, orios::end. - Fixed-record calculation: For zero-based record number
nand record sizeS, the byte offset isn * S. - Strength: A fixed-size record can be retrieved or updated without scanning the entire file.
- Principle:
streamoff offset = static_cast<streamoff>(n) * sizeof(Record);
file.seekg(offset, ios::beg);Here, n is the zero-based record index, Record is the stored fixed-size type, and offset is the resulting byte displacement.
B. Binary file operations
Binary operations transfer bytes directly, avoiding formatted text conversion.
- Output operation:
write(address, count)copiescountbytes from memory to the file. - Input operation:
read(address, count)copies bytes from the file into memory. - Required conversion: The memory address is supplied as
char*orconst char*, commonly throughreinterpret_cast. - Advantages: Numeric values usually occupy fixed space and can be read without parsing decimal characters.
- Restrictions: Raw binary files can depend on type size, byte order, padding, and compiler representation, reducing portability.
- Suitable types: Direct object-byte storage should be limited to trivially copyable data, not objects containing pointers,
std::string, virtual functions, or owning containers.
Record r{101, 86.5};
ofstream out("record.dat", ios::binary);
out.write(reinterpret_cast<const char*>(&r), sizeof(r));IV. User-Defined Records — Integrating Data Models with Streams
Classes and structures can represent complete records, but their file format should match their internal data and portability requirements.
A. Classes and file operations
A class can encapsulate both record data and the operations used to serialize it.
- Text serialization: A member function may write each field with delimiters, allowing values such as an identifier and name to be reconstructed.
- Encapsulation: Private fields remain protected because public functions or overloaded stream operators control file access.
- Operator support:
operator<<andoperator>>can provide a consistent stream interface. - Resource-owning class: A class containing an
fstreamcan open it in a constructor and rely on its destructor for automatic closure. - Safety rule: A class containing
std::stringmust serialize the characters or length explicitly; dumping the object's bytes stores implementation details rather than valid string content.
class Student {
int roll{};
string name;
public:
void save(ostream& out) const {
out << roll << '\n' << name << '\n';
}
};B. Structures and file operations
A structure groups related fields and is commonly used for simple fixed-format records.
- Default accessibility: Structure members are public unless another access specifier is declared.
- Text processing: Individual members can be written using
<<and read using>>orgetline(). - Binary processing: A structure containing only suitable fixed-size values can be transferred with
read()andwrite(). - Fixed-size example:
struct Record { int id; double score; };supports offset calculations usingsizeof(Record). - Layout caution: Padding may occur between members, so raw structure files are not guaranteed to be portable across systems or compilers.
V. Object Lifetime Management — Establishing and Releasing State
Constructors create valid object state, and destructors perform cleanup when that state reaches the end of its lifetime.
A. Manager functions: constructors and destructor
Manager functions are special member functions that govern object initialization, copying, and destruction.
- Constructor identity: A constructor has the same name as its class and has no return type, not even
void. - Automatic call: Construction occurs when an object is created, such as
Account a;. - Overloading: A class may provide several constructors with different parameter lists.
- Destructor identity: A destructor is named
~ClassName()and has neither parameters nor a return type. - Resource role: Constructors may acquire memory or open files; destructors release memory or close associated resources.
B. Default constructor
A default constructor can be invoked without supplying arguments.
- Form:
ClassName();is an explicitly declared default constructor. - Purpose: It establishes predictable initial values instead of leaving fundamental members indeterminate.
- Compiler behavior: If no constructor is user-declared, the compiler may implicitly declare a default constructor.
- Value initialization: Member initializers such as
int count{};set fundamental values to zero.
class Counter {
int value;
public:
Counter() : value(0) {}
};C. Constructor with default arguments
A constructor with default arguments allows omitted trailing arguments to receive predefined values.
- Declaration:
Box(int h = 1, int w = 1);can be called asBox(),Box(5), orBox(5, 8). - Placement rule: After the first defaulted parameter, all following parameters must also have defaults.
- Ambiguity risk: Defining both
Box()andBox(int h = 1)makesBox b;ambiguous because either constructor matches. - Concrete values:
Box(5)assignsh = 5and uses the defaultw = 1.
D. Destructors
A destructor performs final actions immediately before an object's storage is released.
- Invocation: Automatic objects are destroyed when their scope ends; dynamically allocated objects are destroyed by
delete. - Order: Local objects are destroyed in reverse order of completed construction.
- Member destruction: After the destructor body runs, data members and base-class subobjects are destroyed automatically.
- Uniqueness: A class has only one destructor because destructors accept no arguments and cannot be overloaded.
- RAII application: Standard members such as
fstream,string, andvectorclean up their own resources, reducing manual destructor code. - Polymorphism: A base class deleted through a base pointer should generally have a virtual destructor.
E. Parameterized constructor
A parameterized constructor initializes an object from caller-supplied values.
- Purpose: It ensures required information is available at creation, such as
Account("A17", 500.0). - Validation: The constructor can reject invalid state, for example a negative opening balance.
- Overloading: Different parameter lists can support different valid creation paths.
- Direct construction:
Point p(3, 4);passes3and4toPoint(int, int).
class Point {
int x, y;
public:
Point(int xValue, int yValue)
: x(xValue), y(yValue) {}
};F. Copy constructor
A copy constructor creates a new object from an existing object of the same class.
- Usual signature:
ClassName(const ClassName& other)uses a const reference to avoid recursively copying the parameter. - Invocation: It is used in declarations such as
Buffer b = a;and may be used in pass-by-value or return operations. - Compiler-generated copy: The implicit copy constructor performs member-by-member copying.
- Shallow-copy danger: Copying an owning pointer duplicates only its address, potentially causing shared mutation or double deletion.
- Deep copy: A resource-owning class may allocate separate storage and copy the pointed-to elements.
- Modern preference: Standard containers and smart pointers express ownership more safely than manually managed arrays.
G. Initializer lists
A constructor initializer list initializes base classes and members before the constructor body executes.
- Syntax: Initializers follow a colon, as in
Point(int a) : x(a) {}. - Requirement: References,
constmembers, and base classes must be initialized rather than assigned later. - Efficiency: Members are constructed directly with final values instead of being default-constructed and then assigned.
- Actual order: Members initialize in their declaration order inside the class, not the written order in the initializer list.
- Best practice: Write initializers in declaration order to make dependencies clear and avoid warnings.
class FileRecord {
const int id;
fstream file;
public:
FileRecord(int value, const string& path)
: id(value), file(path, ios::in | ios::out) {}
};Did this save you a night before the exam?
LPU Notes is free, and it stays free. Ads cover part of the server bill. The rest comes out of a student's own pocket: the domain, the storage, and keeping the site up through the weeks everyone needs it at once.
The payment button didn't load. An ad blocker or a filtered network is the usual reason. to try again.
Nothing here is ever locked, and nothing unlocks. Chip in only if it was worth it. What it pays for →