default


Keyword: default

The default keyword in C++ is a powerful feature introduced in C++11. It's primarily used in the context of special member functions, allowing the compiler to generate default implementations. This keyword enhances code readability and helps prevent unintended behavior.

Example 1: Basic Usage with Default Constructor

#include <iostream>

class SimpleClass {
public:
    SimpleClass() = default;
    void printMessage() {
        std::cout << "Hello from SimpleClass!" << std::endl;
    }
};

int main() {
    SimpleClass obj;
    obj.printMessage();
    return 0;
}

Explanation

In this example, we use default to explicitly request the compiler to generate a default constructor for SimpleClass. This is equivalent to writing an empty constructor but more expressive and potentially more efficient.

Example 2: Defaulted Copy Constructor and Copy Assignment Operator

#include <iostream>
#include <string>

class Person {
public:
    Person(const std::string& name) : name_(name) {}

    // Defaulted copy constructor
    Person(const Person&) = default;

    // Defaulted copy assignment operator
    Person& operator=(const Person&) = default;

    void printName() const {
        std::cout << "Name: " << name_ << std::endl;
    }

private:
    std::string name_;
};

int main() {
    Person p1("Alice");
    Person p2 = p1;  // Uses defaulted copy constructor
    Person p3("Bob");
    p3 = p1;  // Uses defaulted copy assignment operator

    p1.printName();
    p2.printName();
    p3.printName();

    return 0;
}

Explanation

Example 3: Defaulted Move Operations

#include <iostream>
#include <vector>

class DataHolder {
public:
    DataHolder(std::vector<int> data) : data_(std::move(data)) {}

    // Defaulted move constructor
    DataHolder(DataHolder&&) = default;

    // Defaulted move assignment operator
    DataHolder& operator=(DataHolder&&) = default;

    // Deleted copy operations to enforce move semantics
    DataHolder(const DataHolder&) = delete;
    DataHolder& operator=(const DataHolder&) = delete;

    void printData() const {
        for (int i : data_) {
            std::cout << i << " ";
        }
        std::cout << std::endl;
    }

private:
    std::vector<int> data_;
};

int main() {
    DataHolder d1({1, 2, 3, 4, 5});
    DataHolder d2 = std::move(d1);  // Uses defaulted move constructor

    DataHolder d3({6, 7, 8});
    d3 = std::move(d2);  // Uses defaulted move assignment operator

    d3.printData();

    return 0;
}

Explanation

Example 4: Defaulted Destructor

#include <iostream>
#include <memory>

class Resource {
public:
    Resource() { std::cout << "Resource acquired" << std::endl; }
    ~Resource() { std::cout << "Resource released" << std::endl; }
};

class Manager {
public:
    Manager() : resource_(std::make_unique<Resource>()) {}

    // Defaulted destructor
    ~Manager() = default;

private:
    std::unique_ptr<Resource> resource_;
};

int main() {
    {
        Manager m;
        std::cout << "Manager object created" << std::endl;
    }  // Manager and Resource destructors called here

    std::cout << "End of main" << std::endl;
    return 0;
}

Explanation

Additional Considerations

  1. Rule of Zero: When possible, rely on the Rule of Zero, which states that you should avoid declaring special member functions if the default behavior is sufficient.

  2. Inheritance: Be cautious when using default in inheritance hierarchies. A defaulted destructor in a base class, for example, will not be virtual unless explicitly declared as such.

  3. Performance: Using default can sometimes lead to more efficient code than manually implementing the same functionality, as the compiler has more freedom to optimize.

Summary

The default keyword in C++ is a powerful tool for explicitly requesting compiler-generated implementations of special member functions. It's commonly used for constructors, destructors, copy/move operations, and assignment operators. By using default, you can:

  1. Improve code readability by clearly expressing your intentions.
  2. Ensure that the compiler generates these functions even if you've defined other special member functions.
  3. Potentially improve performance by allowing the compiler to use the most efficient implementation.
  4. Adhere to best practices like the Rule of Zero when appropriate.

Understanding and properly using the default keyword is crucial for writing clean, efficient, and maintainable C++ code, especially when dealing with resource management and object lifecycle.

Related

Previous Page | Course Schedule | Course Content