# What are Initializer Lists?

Initializer lists in C++ are a way to initialize objects or variables of a particular type. They are often used in the context of classes, where they can initialize member variables in the constructor of the class.

# Initializing Member Data with Member Functions 

Initializing member data with member functions is not typically done in C++, as it's preferred to use constructors and initializer lists. However, it is still good to know we can initialize member data with functions for educational purposes.

At this example, **`setName`**, **`setWins`**, and **`setLosses`** member functions are used to initialize the **`name`**, **`wins`**, and **`losses`** member data.

```c
#include <iostream>
#include <string>

// Define the class 'MMAFighter'
class MMAFighter {
public:
    std::string name;  // Declare a string to hold the fighter's name
    int wins;  // Declare an integer to hold the fighter's win count
    int losses;  // Declare an integer to hold the fighter's loss count

    // Member functions to initialize the member data
    void setName(std::string n) {
        name = n;
    }

    void setWins(int w) {
        wins = w;
    }

    void setLosses(int l) {
        losses = l;
    }

    // Declare a member function to display the fighter's record
    void displayRecord() {
        std::cout << "Name: " << name << "\n";
        std::cout << "Wins: " << wins << "\n";
        std::cout << "Losses: " << losses << "\n";
    }
};

int main() {
    MMAFighter fighter1;  // Create an object of MMAFighter class
    fighter1.setName("Conor McGregor");
    fighter1.setWins(22);
    fighter1.setLosses(6);

    fighter1.displayRecord();  // Call the displayRecord function for fighter1
    std::cout << "\n";  // Print a blank line

    MMAFighter fighter2;  // Create another object of MMAFighter class
    fighter2.setName("Khabib Nurmagomedov");
    fighter2.setWins(29);
    fighter2.setLosses(0);

    fighter2.displayRecord();  // Call the displayRecord function for fighter2
    std::cout << "\n";  // Print a blank line

    return 0;
}
```

# Initializer Lists for Member Data Initialization

The initializer list is used in the constructor to initialize the member variables **`name`**, **`wins`**, and **`losses`**. This code defines a **constructor** for the **`MMAFighter`** class that takes three parameters: a **`std::string`** and two **`ints`**.

```c
#include <iostream>
#include <string>

// Define the class 'MMAFighter'
class MMAFighter {
public:
    std::string name;  // Declare a string to hold the fighter's name
    int wins;  // Declare an integer to hold the fighter's win count
    int losses;  // Declare an integer to hold the fighter's loss count

    // Declare a constructor with an initializer list
    MMAFighter(std::string n, int w, int l)
        : name(n),
        wins(w),
        losses(l)
    {
    }

    // Declare a member function to display the fighter's record
    void displayRecord() {
        std::cout << "Name: " << name << "\n";
        std::cout << "Wins: " << wins << "\n";
        std::cout << "Losses: " << losses << "\n";
    }
};

int main() {
    // Create an object of MMAFighter class with initializer list
    MMAFighter fighter1("Conor McGregor", 22, 6);

    fighter1.displayRecord();  // Call the displayRecord function for fighter1
    std::cout << "\n";  // Print a blank line

    // Create another object of MMAFighter class with initializer list
    MMAFighter fighter2("Khabib Nurmagomedov", 29, 0);

    fighter2.displayRecord();  // Call the displayRecord function for fighter2
    std::cout << "\n";  // Print a blank line

    return 0;
}
```

![image](https://github.com/DebugPrivilege/InsightEngineering/assets/63166600/fc49ecbc-4d07-4e29-be17-b2752f3db7f6)



The part that follows the colon **(:)** is the initializer list. This list says that the **`name`** member variable should be initialized with the value of **`n`**, the **`wins`** member variable should be initialized with the value of **`w`**, and the **`losses`** member variable should be initialized with the value of **`l`**.

![image](https://github.com/DebugPrivilege/InsightEngineering/assets/63166600/9fa7c442-7d03-4553-8923-e5aa1f081a7c)


So in this case, the initializer list is : **`name(n)**, **wins(w)**, **losses(l)`**. It provides initial values for the member variables when a new **`MMAFighter`** object is created.

For example, when we create a new MMAFighter:

![image](https://github.com/DebugPrivilege/InsightEngineering/assets/63166600/72af7bab-4dd4-41b0-8b51-0954c5ce101b)



The constructor is called with the parameters **`n = "Conor McGregor", w = 22, and l = 6`**. The initializer list in the constructor then initializes name, wins, and losses with these values.

# What is the difference between the two?

Let's start comparing the two code snippets that we used as examples. The previous code was not using a constructor with an initializer list to initialize the data. Instead, it was manually assigning values to the data members after an object was created. 

An object of the **`MMAFighter`** class was created with the default constructor (no parameters), and then values were manually assigned to the **`name`**, **`wins`**, and **`losses`** data members.

```c
int main() {
    MMAFighter fighter1;  // Create an object of MMAFighter class

    fighter1.name = "Conor McGregor";  // Assign a name to fighter1
    fighter1.wins = 22;  // Assign win count to fighter1
    fighter1.losses = 6;  // Assign loss count to fighter1

    fighter1.displayRecord();  // Call the displayRecord function for fighter1
    std::cout << "\n";  // Print a blank line

    MMAFighter fighter2;  // Create another object of MMAFighter class

    fighter2.name = "Khabib Nurmagomedov";  // Assign a name to fighter2
    fighter2.wins = 29;  // Assign win count to fighter2
    fighter2.losses = 0;  // Assign loss count to fighter2

    fighter2.displayRecord();  // Call the displayRecord function for fighter2
    std::cout << "\n";  // Print a blank line

    return 0;
}
```

In the second code, we pass the values that we want to assign to the **`name`**, **`wins`**, and **`losses`** fields directly to the constructor. The constructor then uses these values to initialize the fields at the same time the object is created. This is a single-step process and considered a best practice.
```c
int main() {
    // Create an object of MMAFighter class with initializer list
    MMAFighter fighter1("Conor McGregor", 22, 6);

    fighter1.displayRecord();  // Call the displayRecord function for fighter1
    std::cout << "\n";  // Print a blank line

    // Create another object of MMAFighter class with initializer list
    MMAFighter fighter2("Khabib Nurmagomedov", 29, 0);

    fighter2.displayRecord();  // Call the displayRecord function for fighter2
    std::cout << "\n";  // Print a blank line

    return 0;
}
```
Review both code snippets and you will see the difference!

# Final Example

Let's close this section with one final example:

```c
#include <windows.h>
#include <iostream>
#include <string>
#include <time.h>

class FileHandler {
private:
    HANDLE fileHandle;  // Declare a HANDLE to hold the file's handle

    // Function to generate a random filename
    std::wstring generateFilename() {
        // Seed the random number generator with the current time
        srand(static_cast<unsigned int>(time(NULL)));
        // Generate a random number
        int randNum = rand();
        // Convert the random number to a string
        std::wstring randNumStr = std::to_wstring(randNum);
        // Return the filename
        return L"C:\\Temp\\testfile_" + randNumStr + L".txt";
    }

    // Function to create a file with the given filename
    void createFile(std::wstring filename) {
        // Create the file
        fileHandle = CreateFileW(
            filename.c_str(),
            GENERIC_WRITE,
            0,
            NULL,
            CREATE_NEW,
            FILE_ATTRIBUTE_NORMAL,
            NULL
        );

        // Check if the file was created successfully
        if (fileHandle == INVALID_HANDLE_VALUE) {
            std::wcout << L"Unable to create file due to error: " << GetLastError() << "\n";
        }
    }

    // Function to write to the file
    void writeToFile() {
        // The data to write to the file
        const wchar_t data[] = L"Hello, World!";
        DWORD bytesWritten;

        // Write the data to the file
        if (!WriteFile(
            fileHandle,
            data,
            wcslen(data) * sizeof(wchar_t),
            &bytesWritten,
            NULL
        )) {
            std::wcout << L"Unable to write to file due to error: " << GetLastError() << "\n";
        }
        else {
            std::wcout << L"File created and written successfully.\n";
        }
    }

    // Function to close the file
    void closeFile() {
        // Check if the file handle is valid
        if (fileHandle != INVALID_HANDLE_VALUE) {
            // Close the file
            CloseHandle(fileHandle);
        }
    }

public:
    FileHandler() : fileHandle(INVALID_HANDLE_VALUE) {
        // Generate a random filename
        std::wstring filename = generateFilename();
        // Create a file with the generated filename
        createFile(filename);
        // Write to the file
        writeToFile();
    }

    ~FileHandler() {
        // Close the file
        closeFile();
    }
};

int main() {
    FileHandler fh;
    return 0;
}
```

The initializer list is specified after the colon (:) following the constructor declaration as we discussed previously. The initializer list initializes the **`fileHandle`** member variable with the value **INVALID_HANDLE_VALUE**. Initializing **`fileHandle`** with **INVALID_HANDLE_VALUE** is useful because it provides a default value indicating that the handle is not valid.

![image](https://github.com/DebugPrivilege/InsightEngineering/assets/63166600/f023fc73-33d1-44fe-beec-66b19ae8a9a5)


