RAII ties a resource's lifetime to an object's scope.

RAII RAII means resource acquisition is initialization: acquire in the constructor and release in the destructor.

RAII Scope

example
raii_scope.cpp
Replay: real traced execution (multi-file project)
#include <iostream>
#include <string>

class ScopeLog {
private:
    std::string name;

public:
    ScopeLog(std::string label) {
        name = label;
        std::cout << "enter=" << name << std::endl;
    }

    ~ScopeLog() {
        std::cout << "leave=" << name << std::endl;
    }
};

int runJob(std::string label, int workUnits) {
    ScopeLog scope(label);
    int total = 0;
    for (int i = 1; i <= workUnits; i++) {
        total += i;
    }
    return total;
}

int main() {
    std::string label = "load";
    int workUnits = 3;

    int total = runJob(label, workUnits);

    std::cout << "total=" << total << std::endl;
    return 0;
}
#include <iostream>
#include <string>

class ScopeLog {
private:
    std::string name;

public:
    ScopeLog(std::string label) {
        name = label;
        std::cout << "enter=" << name << std::endl;
    }

    ~ScopeLog() {
        std::cout << "leave=" << name << std::endl;
    }
};

int runJob(std::string label, int workUnits) {
    ScopeLog scope(label);
    int total = 0;
    for (int i = 1; i <= workUnits; i++) {
        total += i;
    }
    return total;
}

int main() {
    std::string label = "save";
    int workUnits = 3;

    int total = runJob(label, workUnits);

    std::cout << "total=" << total << std::endl;
    return 0;
}
#include <iostream>
#include <string>

class ScopeLog {
private:
    std::string name;

public:
    ScopeLog(std::string label) {
        name = label;
        std::cout << "enter=" << name << std::endl;
    }

    ~ScopeLog() {
        std::cout << "leave=" << name << std::endl;
    }
};

int runJob(std::string label, int workUnits) {
    ScopeLog scope(label);
    int total = 0;
    for (int i = 1; i <= workUnits; i++) {
        total += i;
    }
    return total;
}

int main() {
    std::string label = "sync";
    int workUnits = 3;

    int total = runJob(label, workUnits);

    std::cout << "total=" << total << std::endl;
    return 0;
}
#include <iostream>
#include <string>

class ScopeLog {
private:
    std::string name;

public:
    ScopeLog(std::string label) {
        name = label;
        std::cout << "enter=" << name << std::endl;
    }

    ~ScopeLog() {
        std::cout << "leave=" << name << std::endl;
    }
};

int runJob(std::string label, int workUnits) {
    ScopeLog scope(label);
    int total = 0;
    for (int i = 1; i <= workUnits; i++) {
        total += i;
    }
    return total;
}

int main() {
    std::string label = "load";
    int workUnits = 1;

    int total = runJob(label, workUnits);

    std::cout << "total=" << total << std::endl;
    return 0;
}
#include <iostream>
#include <string>

class ScopeLog {
private:
    std::string name;

public:
    ScopeLog(std::string label) {
        name = label;
        std::cout << "enter=" << name << std::endl;
    }

    ~ScopeLog() {
        std::cout << "leave=" << name << std::endl;
    }
};

int runJob(std::string label, int workUnits) {
    ScopeLog scope(label);
    int total = 0;
    for (int i = 1; i <= workUnits; i++) {
        total += i;
    }
    return total;
}

int main() {
    std::string label = "load";
    int workUnits = 5;

    int total = runJob(label, workUnits);

    std::cout << "total=" << total << std::endl;
    return 0;
}
  1. label ← load, workUnits ← 3

    28int main() {29    std::string label→ load = "load"; //@label="save", "sync"30    int workUnits→ 3 = 3; //@workUnits=1, 53132    int total = runJob(labelload, workUnits3);
  2. int runJob(std::string label, int workUnits)

    19int runJob(std::string labelload, int workUnits3) {20    ScopeLog scope(labelload);21    int total = 0;
  3. ScopeLog(std::string label)

    8public:9    ScopeLog(std::string labelload) {10        name = labelload;11        std::cout << "enter=" << name << std::endl;12    }
    outputenter=load
  4. scope ← (empty), total ← 0

    19int runJob(std::string label, int workUnits) {20    ScopeLog scope→ (empty)(labelload);21    int total→ 0 = 0;22    for (int i = 1; i <= workUnits; i++) {
  5. total ← 1

    pass 1 of 3
    21int total = 0;22for (int i1 = 1; i <= workUnits3; i++) {23    total→ 1 += i1;24}
    All 3 passes — pass 1 is the card above
    passitotal
    110 1
    221 3
    333 6
  6. return total;

    24    }25    return total6;26}
  7. ~ScopeLog()

    14~ScopeLog() {15    std::cout << "leave=" << name << std::endl;16}
    outputleave=load
  8. total ← 6

    32    int total→ 6 = runJob(labelload, workUnits3);3334    std::cout << "total=" << total6 << std::endl;35    return 0;36}
    outputtotal=6
  1. label ← save, workUnits ← 3

    28int main() {29    std::string label→ save = "save";30    int workUnits→ 3 = 3;3132    int total = runJob(labelsave, workUnits3);
  2. int runJob(std::string label, int workUnits)

    19int runJob(std::string labelsave, int workUnits3) {20    ScopeLog scope(labelsave);21    int total = 0;
  3. ScopeLog(std::string label)

    8public:9    ScopeLog(std::string labelsave) {10        name = labelsave;11        std::cout << "enter=" << name << std::endl;12    }
    outputenter=save
  4. scope ← (empty), total ← 0

    19int runJob(std::string label, int workUnits) {20    ScopeLog scope→ (empty)(labelsave);21    int total→ 0 = 0;22    for (int i = 1; i <= workUnits; i++) {
  5. total ← 1

    pass 1 of 3
    21int total = 0;22for (int i1 = 1; i <= workUnits3; i++) {23    total→ 1 += i1;24}
    All 3 passes — pass 1 is the card above
    passitotal
    110 1
    221 3
    333 6
  6. return total;

    24    }25    return total6;26}
  7. ~ScopeLog()

    14~ScopeLog() {15    std::cout << "leave=" << name << std::endl;16}
    outputleave=save
  8. total ← 6

    32    int total→ 6 = runJob(labelsave, workUnits3);3334    std::cout << "total=" << total6 << std::endl;35    return 0;36}
    outputtotal=6
  1. label ← sync, workUnits ← 3

    28int main() {29    std::string label→ sync = "sync";30    int workUnits→ 3 = 3;3132    int total = runJob(labelsync, workUnits3);
  2. int runJob(std::string label, int workUnits)

    19int runJob(std::string labelsync, int workUnits3) {20    ScopeLog scope(labelsync);21    int total = 0;
  3. ScopeLog(std::string label)

    8public:9    ScopeLog(std::string labelsync) {10        name = labelsync;11        std::cout << "enter=" << name << std::endl;12    }
    outputenter=sync
  4. scope ← (empty), total ← 0

    19int runJob(std::string label, int workUnits) {20    ScopeLog scope→ (empty)(labelsync);21    int total→ 0 = 0;22    for (int i = 1; i <= workUnits; i++) {
  5. total ← 1

    pass 1 of 3
    21int total = 0;22for (int i1 = 1; i <= workUnits3; i++) {23    total→ 1 += i1;24}
    All 3 passes — pass 1 is the card above
    passitotal
    110 1
    221 3
    333 6
  6. return total;

    24    }25    return total6;26}
  7. ~ScopeLog()

    14~ScopeLog() {15    std::cout << "leave=" << name << std::endl;16}
    outputleave=sync
  8. total ← 6

    32    int total→ 6 = runJob(labelsync, workUnits3);3334    std::cout << "total=" << total6 << std::endl;35    return 0;36}
    outputtotal=6
  1. label ← load, workUnits ← 1

    28int main() {29    std::string label→ load = "load";30    int workUnits→ 1 = 1;3132    int total = runJob(labelload, workUnits1);
  2. int runJob(std::string label, int workUnits)

    19int runJob(std::string labelload, int workUnits1) {20    ScopeLog scope(labelload);21    int total = 0;
  3. ScopeLog(std::string label)

    8public:9    ScopeLog(std::string labelload) {10        name = labelload;11        std::cout << "enter=" << name << std::endl;12    }
    outputenter=load
  4. scope ← (empty), total ← 0

    19int runJob(std::string label, int workUnits) {20    ScopeLog scope→ (empty)(labelload);21    int total→ 0 = 0;22    for (int i = 1; i <= workUnits; i++) {
  5. total ← 1

    21int total = 0;22for (int i1 = 1; i <= workUnits1; i++) {23    total→ 1 += i1;24}
  6. return total;

    24    }25    return total1;26}
  7. ~ScopeLog()

    14~ScopeLog() {15    std::cout << "leave=" << name << std::endl;16}
    outputleave=load
  8. total ← 1

    32    int total→ 1 = runJob(labelload, workUnits1);3334    std::cout << "total=" << total1 << std::endl;35    return 0;36}
    outputtotal=1
  1. label ← load, workUnits ← 5

    28int main() {29    std::string label→ load = "load";30    int workUnits→ 5 = 5;3132    int total = runJob(labelload, workUnits5);
  2. int runJob(std::string label, int workUnits)

    19int runJob(std::string labelload, int workUnits5) {20    ScopeLog scope(labelload);21    int total = 0;
  3. ScopeLog(std::string label)

    8public:9    ScopeLog(std::string labelload) {10        name = labelload;11        std::cout << "enter=" << name << std::endl;12    }
    outputenter=load
  4. scope ← (empty), total ← 0

    19int runJob(std::string label, int workUnits) {20    ScopeLog scope→ (empty)(labelload);21    int total→ 0 = 0;22    for (int i = 1; i <= workUnits; i++) {
  5. total ← 1

    pass 1 of 5
    21int total = 0;22for (int i1 = 1; i <= workUnits5; i++) {23    total→ 1 += i1;24}
    All 5 passes — pass 1 is the card above
    passitotal
    110 1
    221 3
    333 6
    446 10
    5510 15
  6. return total;

    24    }25    return total15;26}
  7. ~ScopeLog()

    14~ScopeLog() {15    std::cout << "leave=" << name << std::endl;16}
    outputleave=load
  8. total ← 15

    32    int total→ 15 = runJob(labelload, workUnits5);3334    std::cout << "total=" << total15 << std::endl;35    return 0;36}
    outputtotal=15

Enter, Work, Leave

  1. runJob creates ScopeLog scope(label).
  2. The constructor prints enter=load.
  3. The loop adds work units into total.
  4. Leaving runJob destroys scope.
  5. The destructor prints leave=load automatically. | Moment | What happens | | --- | --- | | enter scope | acquire/log load | | inside scope | calculate 1 + 2 + 3 | | leave scope | release/log load |

Exercise: raii_scope.cpp

Create a scope logger that prints on entry and exit while a small job computes a total