Modernes C++ programmieren

Okt 20, 2024

listings-Chap20-README-onepage.md

Listings of Chap20.docx

This is the list of listings on one page. You can also view a linked summary.

GodboltId:4536hxvEK

Book listing lst-0003-book.cpp:

// https://godbolt.org/z/4536hxvEK 
int value = 42;
int& valueRef = value;  // Reference; no address operator & needed
valueRef = 18;          // no dereference operator * needed
cout << value << "\n";  // Output: 18

Godbolt Listing lst-0003-godb.cpp, https://godbolt.org/z/4536hxvEK:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4536hxvEK 
int value = 42;
int& valueRef = value;  // Reference; no address operator & needed
valueRef = 18;          // no dereference operator * needed
cout << value << "\n";  // Output: 18

Listing 20.1: Pointers can be assigned new addresses during their lifetime.

Book listing lst-0004-book.cpp:

// https://godbolt.org/z/7GEWYeoc9
#include <vector>
#include <iostream>
using std::vector; using std::cout; using std::ostream;
ostream& printVector(ostream& os, const vector<int> &arg) { // Helper function
    for(int w : arg) os << w << " "; return os;
}
int main() {
    vector<int> values{ };
    values.reserve(50);                  // Guarantee space for 50 values
    int *largest = nullptr;              // Initialize with a special value
    for(int w : { 20, 2, 30, 15, 81, 104, 70, 2, }) {
        values.push_back(w);
        if(!largest || *largest < w ) {  // Dereference to value
            largest = &(values.back());  // Remember new address; hence not '*'
        }
    }
    printVector(cout, values) << "\n";   // Output: 20 2 30 15 81 104 70 2
    // largest now contains the address of 104:
    *largest = -999;                     // dereference; also overwrite value
    printVector(cout, values) << "\n";   // Output: 20 2 30 15 81 –999 70 2
}

Godbolt Listing lst-0004-godb.cpp, https://godbolt.org/z/7GEWYeoc9:

//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/7GEWYeoc9
#include <vector>
#include <iostream>
using std::vector; using std::cout; using std::ostream;
ostream& printVector(ostream& os, const vector<int> &arg) { // Helper function
    for(int w : arg) os << w << " "; return os;
}
int main() {
    vector<int> values{ };
    values.reserve(50);                  // Guarantee space for 50 values
    int *largest = nullptr;              // Initialize with a special value
    for(int w : { 20, 2, 30, 15, 81, 104, 70, 2, }) {
        values.push_back(w);
        if(!largest || *largest < w ) {  // Dereference to value
            largest = &(values.back());  // Remember new address; hence not '*'
        }
    }
    printVector(cout, values) << "\n";   // Output: 20 2 30 15 81 104 70 2
    // largest now contains the address of 104:
    *largest = -999;                     // dereference; also overwrite value
    printVector(cout, values) << "\n";   // Output: 20 2 30 15 81 –999 70 2
}

Listing 20.2: Returning by value can create a copy.

Book listing lst-0007-book.cpp:

Planet createPlanet(const Event &evt) {  // return by value
    Planet result{"Earth"};              // stack object
    result.setLocation(evt.getPosition());
    return result;                       // return creates (potential) copy
}

Listing 20.3: Returning as a pointer only copies the pointer, not the object.

Book listing lst-0008-book.cpp:

// return as (smart) pointer:
unique_ptr<Planet> createPlanet(const Event &evt) {
    unique_ptr<Planet> result{ new Planet{"Venus"} };  // heap object
    result->setLocation(evt.getPosition());
    return result; // passes the address
}

Listing 21.4: In the following examples, I use Image as a class for which I want a pointer.

Book listing lst-0010-book.cpp:

// https://godbolt.org/z/ehhGPjabz 
#include <string>
#include <vector>
class Image {
    std::vector<char> imageData_;
public:
    explicit Image(const std::string& filename) { /* Load image */ }
    void draw() const { /* Paint image */ };
};

Godbolt Listing lst-0010-godb.cpp, https://godbolt.org/z/ehhGPjabz:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/ehhGPjabz 
#include <string>
#include <vector>
class Image {
    std::vector<char> imageData_;
public:
    explicit Image(const std::string& filename) { /* Load image */ }
    void draw() const { /* Paint image */ };
};

Listing 20.4: unique_ptr as data field, return value, and local variable.

Book listing lst-0011-book.cpp:

// https://godbolt.org/z/aTTejrnWE
#include <memory>                       // unique_ptr
#include <string>
#include <iostream>
using std::unique_ptr; using std::string;
class Component { };                    // Dummy window hierarchy
class Label : public Component { };
class Textfield : public Component { };
class Button : public Component {
public:
    int id_;                            // ID to distinguish the buttons
    explicit Button(int id) : id_{id} {}
};
class Window { };
class MyDialog : public Window {
    string title_;
    unique_ptr<Label> lblFirstName_{new Label{}};         // lots of data fields
    unique_ptr<Textfield> txtFirstName_{new Textfield{}}; // … tied to the lifetime
    unique_ptr<Label> lblLastName_{new Label{}};          // … of the class
    unique_ptr<Textfield> txtLastName_{new Textfield{}};
    unique_ptr<Button> btnOk_{new Button{1}};
    unique_ptr<Button> btnCancel_{new Button{2}};
public:
    explicit MyDialog(const string& title) : title_{title} {}
    unique_ptr<Button> showModal()
        { return std::move(btnOk_); }    // Placeholder code; OK pressed
};
unique_ptr<MyDialog> createDialog() {
    return unique_ptr<MyDialog>{ // temporary value
        new MyDialog{"Please enter name"}};
}
int showDialog() {
    unique_ptr<MyDialog> dialog = createDialog();         // local variable
    unique_ptr<Button> pressed = dialog->showModal();     // return value
    return pressed->id_;
}
int main() {
    int pressed_id = showDialog();
    if(pressed_id == 1) {
        std::cout << "Thank you for pressing OK\n";
    }
}

Godbolt Listing lst-0011-godb.cpp, https://godbolt.org/z/aTTejrnWE:

//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/aTTejrnWE
#include <memory>                       // unique_ptr
#include <string>
#include <iostream>
using std::unique_ptr; using std::string;
class Component { };                    // Dummy window hierarchy
class Label : public Component { };
class Textfield : public Component { };
class Button : public Component {
public:
    int id_;                            // ID to distinguish the buttons
    explicit Button(int id) : id_{id} {}
};
class Window { };
class MyDialog : public Window {
    string title_;
    unique_ptr<Label> lblFirstName_{new Label{}};         // lots of data fields
    unique_ptr<Textfield> txtFirstName_{new Textfield{}}; // … tied to the lifetime
    unique_ptr<Label> lblLastName_{new Label{}};          // … of the class
    unique_ptr<Textfield> txtLastName_{new Textfield{}};
    unique_ptr<Button> btnOk_{new Button{1}};
    unique_ptr<Button> btnCancel_{new Button{2}};
public:
    explicit MyDialog(const string& title) : title_{title} {}
    unique_ptr<Button> showModal()
        { return std::move(btnOk_); }    // Placeholder code; OK pressed
};
unique_ptr<MyDialog> createDialog() {
    return unique_ptr<MyDialog>{ // temporary value
        new MyDialog{"Please enter name"}};
}
int showDialog() {
    unique_ptr<MyDialog> dialog = createDialog();         // local variable
    unique_ptr<Button> pressed = dialog->showModal();     // return value
    return pressed->id_;
}
int main() {
    int pressed_id = showDialog();
    if(pressed_id == 1) {
        std::cout << "Thank you for pressing OK\n";
    }
}

Listing 20.5: A game board with various objects.

Book listing lst-0013-book.cpp:

// https://godbolt.org/z/4KP91z1bq
#include <vector>
#include <iostream>
#include <memory>                    // shared_ptr
#include <random>                    // uniform_int_distribution, random_device
namespace {                          // Beginning of the anonymous namespace
using std::shared_ptr; using std::make_shared;
using std::vector; using std::cout;
struct Asteroid {
    int points_ = 100;
    int structure_ = 10;
};
struct Ship {
    shared_ptr<Asteroid> firedLastOn_{};
    int score_ = 0;
    int firepower = 1;
    bool fireUpon(shared_ptr<Asteroid> a);
};
struct GameBoard {
    vector<shared_ptr<Asteroid>> asteroids_;
    explicit GameBoard(int nAsteroids);
    bool shipFires(Ship& ship);
};
// Implementation of Ship
bool Ship::fireUpon(shared_ptr<Asteroid> a) {
    if(!a) return false;             // invalid asteroid
    a->structure_ -= firepower;
    if(a.get() == firedLastOn_.get())
        firepower *= 2 ;             // increase damage
    else
        firepower = 1;               // reset
    firedLastOn_ = a;
    return a->structure_ <= 0;       // destroyed?
}
// Implementation of GameBoard
GameBoard::GameBoard(int nAsteroids) : asteroids_{}
{   // some standard asteroids
    for(int idx=0; idx<nAsteroids; ++idx)
        asteroids_.push_back( make_shared<Asteroid>() );
}
int rollDice(int min, int max) {
    /* static std::default_random_engine e{}; */  // Pseudo-random generator
    static std::random_device e{};   // random generator
    return std::uniform_int_distribution<int>{min, max}(e); // roll dice
}
bool GameBoard::shipFires(Ship &ship) {
    int idx = rollDice(0, asteroids_.size()-1);
    bool broken = ship.fireUpon(asteroids_[idx]);
    if(broken) {
        ship.score_ += asteroids_[idx]->points_;
        asteroids_.erase(asteroids_.begin()+idx);  // remove
    }
    return asteroids_.size() == 0;                 // everything is destroyed
}
} // End of the anonymous namespace
int main() {
    GameBoard game{10};                            // 10 asteroids
    Ship ship{};
    for(int idx = 0; idx < 85; ++idx) {            // 85 shots
        if(game.shipFires(ship)) {
            cout << "The space is empty after " << idx+1 << " shots. ";
            break;
        }
    }
    cout << "You have scored " << ship.score_ << " points.\n";
}

Godbolt Listing lst-0013-godb.cpp, https://godbolt.org/z/4KP91z1bq:

//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/4KP91z1bq
#include <vector>
#include <iostream>
#include <memory>                    // shared_ptr
#include <random>                    // uniform_int_distribution, random_device
namespace {                          // Beginning of the anonymous namespace
using std::shared_ptr; using std::make_shared;
using std::vector; using std::cout;
struct Asteroid {
    int points_ = 100;
    int structure_ = 10;
};
struct Ship {
    shared_ptr<Asteroid> firedLastOn_{};
    int score_ = 0;
    int firepower = 1;
    bool fireUpon(shared_ptr<Asteroid> a);
};
struct GameBoard {
    vector<shared_ptr<Asteroid>> asteroids_;
    explicit GameBoard(int nAsteroids);
    bool shipFires(Ship& ship);
};
// Implementation of Ship
bool Ship::fireUpon(shared_ptr<Asteroid> a) {
    if(!a) return false;             // invalid asteroid
    a->structure_ -= firepower;
    if(a.get() == firedLastOn_.get())
        firepower *= 2 ;             // increase damage
    else
        firepower = 1;               // reset
    firedLastOn_ = a;
    return a->structure_ <= 0;       // destroyed?
}
// Implementation of GameBoard
GameBoard::GameBoard(int nAsteroids) : asteroids_{}
{   // some standard asteroids
    for(int idx=0; idx<nAsteroids; ++idx)
        asteroids_.push_back( make_shared<Asteroid>() );
}
int rollDice(int min, int max) {
    /* static std::default_random_engine e{}; */  // Pseudo-random generator
    static std::random_device e{};   // random generator
    return std::uniform_int_distribution<int>{min, max}(e); // roll dice
}
bool GameBoard::shipFires(Ship &ship) {
    int idx = rollDice(0, asteroids_.size()-1);
    bool broken = ship.fireUpon(asteroids_[idx]);
    if(broken) {
        ship.score_ += asteroids_[idx]->points_;
        asteroids_.erase(asteroids_.begin()+idx);  // remove
    }
    return asteroids_.size() == 0;                 // everything is destroyed
}
} // End of the anonymous namespace
int main() {
    GameBoard game{10};                            // 10 asteroids
    Ship ship{};
    for(int idx = 0; idx < 85; ++idx) {            // 85 shots
        if(game.shipFires(ship)) {
            cout << "The space is empty after " << idx+1 << " shots. ";
            break;
        }
    }
    cout << "You have scored " << ship.score_ << " points.\n";
}

Listing 20.6: When a raw pointer owns an object, the potential errors are often hard to detect.

Book listing lst-0016-book.cpp:

// https://godbolt.org/z/Y4sMdzde8
struct StereoImage {
    Image* right_;         // (ERR) raw pointer
    Image* left_;          // (ERR) raw pointer
    StereoImage(const string& nameBase)          // construct
      : right_{new Image{nameBase+"right.jpg"}}  // okay
      , left_{new Image{nameBase+"left.jpg"}}    // dangerous
      { }
    ~StereoImage() {       // remove
        delete right_; delete left_;
    }
    StereoImage(const StereoImage&) = delete;    // no copy
    StereoImage& operator=(const StereoImage&) = delete; // no assignment
};
int main() {
    Image* image = new Image{"image.jpg"};       // (ERR) a raw pointer?
    StereoImage stereo{"3d"};
    delete image;
}

Godbolt Listing lst-0016-godb.cpp, https://godbolt.org/z/Y4sMdzde8:

//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/Y4sMdzde8
struct StereoImage {
    Image* right_;         // (ERR) raw pointer
    Image* left_;          // (ERR) raw pointer
    StereoImage(const string& nameBase)          // construct
      : right_{new Image{nameBase+"right.jpg"}}  // okay
      , left_{new Image{nameBase+"left.jpg"}}    // dangerous
      { }
    ~StereoImage() {       // remove
        delete right_; delete left_;
    }
    StereoImage(const StereoImage&) = delete;    // no copy
    StereoImage& operator=(const StereoImage&) = delete; // no assignment
};
int main() {
    Image* image = new Image{"image.jpg"};       // (ERR) a raw pointer?
    StereoImage stereo{"3d"};
    delete image;
}

Listing 20.7: “primes” contains pointers to another container.

Book listing lst-0018-book.cpp:

// https://godbolt.org/z/W4W61h4Kv
#include <vector>
#include <numeric>     // iota
#include <iostream>
using std::vector; using std::cout;
struct Number {        // representative of a large, expensive object
    unsigned long val_;
    Number(unsigned long val) : val_{val} {}
    Number() : val_{0} {}
};
/* determines whether z is a prime number based on previous prime numbers */
bool isPrime(const Number& z, const vector<Number*> primes) {
    for(Number* p : primes) {
        if((p->val_*p->val_) > z.val_) return true;   // too large
        if(z.val_ % p->val_ == 0) return false;       // is a divisor
    }
    return true;
}
int main() {
    vector<Number> allNumbers(98);  // 98 zero-initialized elements
    std::iota(begin(allNumbers), end(allNumbers), 3); // 3..100
    /* allNumbers now contains {3..100} */
    vector<Number*> primes{};       // stores determined prime numbers
    Number two{2};
    primes.push_back(&two);         // the 2 is needed
    for(Number &z : allNumbers) {   // iterate over all numbers
        if(isPrime(z, primes)) {
            primes.push_back( &z ); // store address
        }
    }
    /* Output the rest */
    for(Number* p : primes)
        cout << p->val_ << " ";
    cout << "\n";
}

Godbolt Listing lst-0018-godb.cpp, https://godbolt.org/z/W4W61h4Kv:

//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/W4W61h4Kv
#include <vector>
#include <numeric>     // iota
#include <iostream>
using std::vector; using std::cout;
struct Number {        // representative of a large, expensive object
    unsigned long val_;
    Number(unsigned long val) : val_{val} {}
    Number() : val_{0} {}
};
/* determines whether z is a prime number based on previous prime numbers */
bool isPrime(const Number& z, const vector<Number*> primes) {
    for(Number* p : primes) {
        if((p->val_*p->val_) > z.val_) return true;   // too large
        if(z.val_ % p->val_ == 0) return false;       // is a divisor
    }
    return true;
}
int main() {
    vector<Number> allNumbers(98);  // 98 zero-initialized elements
    std::iota(begin(allNumbers), end(allNumbers), 3); // 3..100
    /* allNumbers now contains {3..100} */
    vector<Number*> primes{};       // stores determined prime numbers
    Number two{2};
    primes.push_back(&two);         // the 2 is needed
    for(Number &z : allNumbers) {   // iterate over all numbers
        if(isPrime(z, primes)) {
            primes.push_back( &z ); // store address
        }
    }
    /* Output the rest */
    for(Number* p : primes)
        cout << p->val_ << " ";
    cout << "\n";
}

Listing 20.8: Do not return addresses of function-local objects.

Book listing lst-0021-book.cpp:

vector<Number*> primePointers(unsigned long upTo) { // (ERR) Vector of pointers is suspicious
    vector<Number> allNumbers;
    vector<Number*> primes{};
    // …
    for(Number &z : allNumbers)
        if(isPrime(z, primes))
            primes.push_back( &z ); // store address
    return primes;   // (ERR) Pointers to function-local objects
}

Listing 20.9: With raw pointers pointing to a C-array, you can perform arithmetic.

Book listing lst-0026-book.cpp:

// https://godbolt.org/z/a5b6qMo9h
#include <iostream>
int main() {
    int carray[10] = { 1,1 };             // initialized to { 1,1,0,0,0,0,0,0,0,0 }
    int* end = carray+10;                 // pointer past the last element
    for(int* p =carray+2; p != end; ++p) {
        *p = *(p-1) + *(p-2);             // adds the previous two numbers
    }
    for(int const * p=carray; p != end; ++p)
        std::cout << *p << " ";
    std::cout << "\n";
}

Godbolt Listing lst-0026-godb.cpp, https://godbolt.org/z/a5b6qMo9h:

//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/a5b6qMo9h
#include <iostream>
int main() {
    int carray[10] = { 1,1 };             // initialized to { 1,1,0,0,0,0,0,0,0,0 }
    int* end = carray+10;                 // pointer past the last element
    for(int* p =carray+2; p != end; ++p) {
        *p = *(p-1) + *(p-2);             // adds the previous two numbers
    }
    for(int const * p=carray; p != end; ++p)
        std::cout << *p << " ";
    std::cout << "\n";
}

Listing 20.10: C-arrays decay to raw pointers as parameters.

Book listing lst-0030-book.cpp:

// https://godbolt.org/z/1qx16Gr61 
#include <iostream>
void fibonacci(int data[], int* end) {
    for(int* p = data+2; p != end; ++p) {
        *p = *(p-1) + *(p-2);
    }
}
std::ostream& print(std::ostream &os, int data[], int* end) {
    for(int const * p=data; p != end; ++p)
        std::cout << *p << " ";
    return os;
}
int main() {
    int carray[10] = { 1,1 }; // initialized to { 1,1,0,0,0,0,0,0,0,0 }
    fibonacci(carray, carray+10);
    print(std::cout, carray, carray+10) << "\n";
}

Godbolt Listing lst-0030-godb.cpp, https://godbolt.org/z/1qx16Gr61:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/1qx16Gr61 
#include <iostream>
void fibonacci(int data[], int* end) {
    for(int* p = data+2; p != end; ++p) {
        *p = *(p-1) + *(p-2);
    }
}
std::ostream& print(std::ostream &os, int data[], int* end) {
    for(int const * p=data; p != end; ++p)
        std::cout << *p << " ";
    return os;
}
int main() {
    int carray[10] = { 1,1 }; // initialized to { 1,1,0,0,0,0,0,0,0,0 }
    fibonacci(carray, carray+10);
    print(std::cout, carray, carray+10) << "\n";
}

Listing 20.11: “unique_ptr” works with the dynamic C-array.

Book listing lst-0034-book.cpp:

// https://godbolt.org/z/h3q839x8r
#include <memory>      // unique_ptr
#include <iostream>    // cout
std::unique_ptr<int[]> createData(size_t sz) {
    return std::unique_ptr<int[]>(new int[sz]);
}
void fibonacci(int data[], int* end) {
    for(int* p = data+2; p != end; ++p) {
        *p = *(p-1) + *(p-2);
    }
}
std::ostream& print(std::ostream &os, int data[], int* end) {
    for(int const* p = data; p != end; ++p)
        std::cout << *p << " ";
    return os;
}
int main() {
    std::unique_ptr<int[]> data { createData(10) };
    data[0] = 1; // set values in the array through the unique_ptr
    data[1] = 1;
    fibonacci(data.get(), data.get()+10); // get the C-array pointer with get()
    print(std::cout, data.get(), data.get()+10) << "\n";
}

Godbolt Listing lst-0034-godb.cpp, https://godbolt.org/z/h3q839x8r:

//#(compile) c++; compiler:g141; options:-O1 -std=c++23; libs:-
// https://godbolt.org/z/h3q839x8r
#include <memory>      // unique_ptr
#include <iostream>    // cout
std::unique_ptr<int[]> createData(size_t sz) {
    return std::unique_ptr<int[]>(new int[sz]);
}
void fibonacci(int data[], int* end) {
    for(int* p = data+2; p != end; ++p) {
        *p = *(p-1) + *(p-2);
    }
}
std::ostream& print(std::ostream &os, int data[], int* end) {
    for(int const* p = data; p != end; ++p)
        std::cout << *p << " ";
    return os;
}
int main() {
    std::unique_ptr<int[]> data { createData(10) };
    data[0] = 1; // set values in the array through the unique_ptr
    data[1] = 1;
    fibonacci(data.get(), data.get()+10); // get the C-array pointer with get()
    print(std::cout, data.get(), data.get()+10) << "\n";
}

GodboltId:s6sss481E

Book listing lst-0038-book.cpp:

// https://godbolt.org/z/s6sss481E 
const char vimes[13] = "Samuel Vimes"; // const char[13]
const char colon[] = "Fred Colon";     // const char[11]
const char* nobby = "Nobby Nobbs";     // const char[12]

Godbolt Listing lst-0038-godb.cpp, https://godbolt.org/z/s6sss481E:

//#(execute) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/s6sss481E 
const char vimes[13] = "Samuel Vimes"; // const char[13]
const char colon[] = "Fred Colon";     // const char[11]
const char* nobby = "Nobby Nobbs";     // const char[12]

Listing 20.12: With “string”, you often don’t even notice that text literals are “const char[]”.

Book listing lst-0039-book.cpp:

// https://godbolt.org/z/oKsz7d55T 
#include <string>
#include <iostream>                    // cout
using std::string; using std::cout;
string greet(string name) {
    return name + "!";                 // string operator+(string, const char*)
}
int main() {
    string name{ "Havalock Vetinari" };// explicit: string(const char*)
    cout << "Angua";                   // ostream& operator<<(ostream&, const char*)
    cout <<                            // ostream& operator<<(ostream, string)
      greet("Carrot Ironfoundersson"); // implicitly: string(const char*)
}

Godbolt Listing lst-0039-godb.cpp, https://godbolt.org/z/oKsz7d55T:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/oKsz7d55T 
#include <string>
#include <iostream>                    // cout
using std::string; using std::cout;
string greet(string name) {
    return name + "!";                 // string operator+(string, const char*)
}
int main() {
    string name{ "Havalock Vetinari" };// explicit: string(const char*)
    cout << "Angua";                   // ostream& operator<<(ostream&, const char*)
    cout <<                            // ostream& operator<<(ostream, string)
      greet("Carrot Ironfoundersson"); // implicitly: string(const char*)
}

Listing 20.13: Retrieve iterators with “begin” and “end”.

Book listing lst-0040-book.cpp:

// https://godbolt.org/z/4nqz4ed4W 
#include <vector>
#include <iostream> // cout

using std::vector;
int main() {
    vector data{ 5,4,3,2,1 };
    vector<int>::const_iterator end = data.end(); // or end(data)
    for(vector<int>::const_iterator it = data.begin(); it!=end; ++it) {
        std::cout << *it << " ";
    }
    std::cout << "\n";
}

Godbolt Listing lst-0040-godb.cpp, https://godbolt.org/z/4nqz4ed4W:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/4nqz4ed4W 
#include <vector>
#include <iostream> // cout

using std::vector;
int main() {
    vector data{ 5,4,3,2,1 };
    vector<int>::const_iterator end = data.end(); // or end(data)
    for(vector<int>::const_iterator it = data.begin(); it!=end; ++it) {
        std::cout << *it << " ";
    }
    std::cout << "\n";
}

Listing 20.14: You can use raw pointers like iterators.

Book listing lst-0041-book.cpp:

// https://godbolt.org/z/zsqKz76cj 
#include <iostream>   // cout
#include <iterator>   // ostream_iterator
#include <algorithm>  // copy, ranges::copy
int main () {
  int data[6] = { 1, 2, 3, 7, 9, 10 };
  std::ostream_iterator<int> out_it (std::cout,", ");
  std::copy(data, data+6, out_it);            // Pointers as iterators
  std::cout << "\n";                          // Output: 1, 2, 3, 7, 9, 10
  std::ranges::copy(data, out_it);            // C-array pointer as range
  std::cout << "\n";                          // Output: 1, 2, 3, 7, 9, 10
}

Godbolt Listing lst-0041-godb.cpp, https://godbolt.org/z/zsqKz76cj:

//#(compile) c++; compiler:g132; options:-O3 -std=c++23; libs:-
// https://godbolt.org/z/zsqKz76cj 
#include <iostream>   // cout
#include <iterator>   // ostream_iterator
#include <algorithm>  // copy, ranges::copy
int main () {
  int data[6] = { 1, 2, 3, 7, 9, 10 };
  std::ostream_iterator<int> out_it (std::cout,", ");
  std::copy(data, data+6, out_it);            // Pointers as iterators
  std::cout << "\n";                          // Output: 1, 2, 3, 7, 9, 10
  std::ranges::copy(data, out_it);            // C-array pointer as range
  std::cout << "\n";                          // Output: 1, 2, 3, 7, 9, 10
}

Listing 20.15: Is it worth saving the release of memory?

Book listing lst-0042-book.cpp:

// https://godbolt.org/z/xE1TWx1ve
#include <map>
#include <memory> // unique_ptr
#include <string>
#include <iostream>
#include <chrono> // time measurement
using std::map; using std::cout; using std::endl; using namespace std::chrono;
struct Node {
  std::unique_ptr<int> d_;
  Node() : Node{0}  { }
  explicit Node(int d) : d_{ new int } { *d_ = d; }     // also some memory
  friend bool operator<(const Node& a, const Node& b) {return *a.d_<*b.d_;}
  friend bool operator==(const Node& a, const Node& b) {return *a.d_==*b.d_;}
};
long long millisSince(steady_clock::time_point start) { // Helper for time measurement
  return duration_cast<milliseconds>(steady_clock::now()-start).count();
}

int main() {
  std::unique_ptr<map<int,Node>> huge{ new map<int,Node>{} };
  cout << "Building..." << endl;
  steady_clock::time_point start = steady_clock::now();
  for(int idx=0; idx < 100*1000*1000; ++idx) {   // massive amount in the map
      (*huge)[idx] = Node{idx};
  }
  cout << "Done: " << millisSince(start) << " ms" << endl; // timing here
  start = steady_clock::now();
  huge.reset();                                            // cleanup here
  cout << "End: " << millisSince(start) << " ms" << endl;  // timing here
}

Godbolt Listing lst-0042-godb.cpp, https://godbolt.org/z/xE1TWx1ve:

//#(compile) c++; compiler:g141; options:-O1 -std=c++23 -Wall -Wextra; libs:-
// https://godbolt.org/z/xE1TWx1ve
#include <map>
#include <memory> // unique_ptr
#include <string>
#include <iostream>
#include <chrono> // time measurement
using std::map; using std::cout; using std::endl; using namespace std::chrono;
struct Node {
  std::unique_ptr<int> d_;
  Node() : Node{0}  { }
  explicit Node(int d) : d_{ new int } { *d_ = d; }     // also some memory
  friend bool operator<(const Node& a, const Node& b) {return *a.d_<*b.d_;}
  friend bool operator==(const Node& a, const Node& b) {return *a.d_==*b.d_;}
};
long long millisSince(steady_clock::time_point start) { // Helper for time measurement
  return duration_cast<milliseconds>(steady_clock::now()-start).count();
}

int main() {
  std::unique_ptr<map<int,Node>> huge{ new map<int,Node>{} };
  cout << "Building..." << endl;
  steady_clock::time_point start = steady_clock::now();
  for(int idx=0; idx < 100*1000*1000; ++idx) {   // massive amount in the map
      (*huge)[idx] = Node{idx};
  }
  cout << "Done: " << millisSince(start) << " ms" << endl; // timing here
  start = steady_clock::now();
  huge.reset();                                            // cleanup here
  cout << "End: " << millisSince(start) << " ms" << endl;  // timing here
}