wk03_memory


Memory Management

Comprehensive example that demonstrates the use of raw pointers, smart pointers (std::shared_ptr), and std::unique_ptr in the context of scientific computing and simulations. This example will include a memory manager for a 3D grid, a particle system simulation, and a grid ownership model.

Resources (C++ Tutorial)

algorithm, auto, command_line_arguments, constructor, destructor, initializer_list, iostream, memory, namespace, private, protected, public, push_back, random, range-based, raw_pointer, smart_pointers, sstream, std::mt19937, std::random_device, std::shared_ptr, std::uniform_real_distribution, std::unique_ptr, std::weak_ptr, template, vector

Implementation

#include <iostream>
#include <vector>
#include <memory>
#include <random>

// Memory Manager for 3D grid using raw pointers
class MemoryManager {
public:
    MemoryManager(int x, int y, int z) : x_(x), y_(y), z_(z) {
        std::cout << "Allocating 3D grid of size " << x_ << " x " << y_ << " x " << z_ << std::endl;
        grid_ = new double**[x_];
        for (int i = 0; i < x_; ++i) {
            grid_[i] = new double*[y_];
            for (int j = 0; j < y_; ++j) {
                grid_[i][j] = new double[z_];
            }
        }
    }

    ~MemoryManager() {
        std::cout << "Deallocating 3D grid" << std::endl;
        for (int i = 0; i < x_; ++i) {
            for (int j = 0; j < y_; ++j) {
                delete[] grid_[i][j];
            }
            delete[] grid_[i];
        }
        delete[] grid_;
    }

    void setValue(int x, int y, int z, double value) {
        if (x < x_ && y < y_ && z < z_) {
            grid_[x][y][z] = value;
        }
    }

    double getValue(int x, int y, int z) const {
        if (x < x_ && y < y_ && z < z_) {
            return grid_[x][y][z];
        }
        return 0.0; // Handle out of bounds
    }

private:
    int x_, y_, z_;
    double*** grid_;
};

// Particle class for particle system simulation
class Particle {
public:
    Particle(double x, double y, double z) : x_(x), y_(y), z_(z) {}
    void move(double dx, double dy, double dz) {
        x_ += dx; y_ += dy; z_ += dz;
    }
    void print() const {
        std::cout << "Particle at (" << x_ << ", " << y_ << ", " << z_ << ")" << std::endl;
    }

private:
    double x_, y_, z_;
};

// Particle system using std::shared_ptr
class ParticleSystem {
public:
    void addParticle(double x, double y, double z) {
        particles_.push_back(std::make_shared<Particle>(x, y, z));
    }

    void moveParticles() {
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_real_distribution<> dis(-0.1, 0.1);

        for (auto& particle : particles_) {
            particle->move(dis(gen), dis(gen), dis(gen));
        }
    }

    void printParticles() const {
        for (const auto& particle : particles_) {
            particle->print();
        }
    }

private:
    std::vector<std::shared_ptr<Particle>> particles_;
};

// Grid class for unique ownership demonstration
class Grid {
public:
    Grid(int size) : size_(size) {
        std::cout << "Creating Grid of size " << size_ << std::endl;
    }
    ~Grid() {
        std::cout << "Destroying Grid of size " << size_ << std::endl;
    }
    int getSize() const { return size_; }

private:
    int size_;
};

// Simulation class using std::unique_ptr for Grid ownership
class Simulation {
public:
    Simulation(int gridSize) : grid_(std::make_unique<Grid>(gridSize)) {}
    void run() {
        std::cout << "Running simulation with grid size " << grid_->getSize() << std::endl;
    }

private:
    std::unique_ptr<Grid> grid_;
};

int main() {
    // Demonstrate MemoryManager with raw pointers
    {
        MemoryManager mm(4, 4, 4);
        mm.setValue(2, 2, 2, 3.14);
        std::cout << "Value at (2, 2, 2): " << mm.getValue(2, 2, 2) << std::endl;
    }

    std::cout << "\n";

    // Demonstrate ParticleSystem with std::shared_ptr
    {
        ParticleSystem ps;
        ps.addParticle(0, 0, 0);
        ps.addParticle(1, 1, 1);
        std::cout << "Initial particle positions:" << std::endl;
        ps.printParticles();
        ps.moveParticles();
        std::cout << "Particle positions after movement:" << std::endl;
        ps.printParticles();
    }

    std::cout << "\n";

    // Demonstrate Simulation with std::unique_ptr
    {
        Simulation sim(10);
        sim.run();
    }

    return 0;
}

This comprehensive example demonstrates the use of raw pointers, std::shared_ptr, and std::unique_ptr in scientific computing contexts:

  1. Raw Pointers: The MemoryManager class uses raw pointers to manage a 3D grid, which could be used in fluid dynamics simulations. It demonstrates manual memory management with proper allocation and deallocation.

  2. std::shared_ptr: The ParticleSystem class uses std::shared_ptr to manage particles in a particle system simulation. This ensures that memory is automatically released when particles are no longer in use, and allows for easy sharing of particle data if needed.

  3. std::unique_ptr: The Simulation class uses std::unique_ptr to manage the ownership of a Grid object. This ensures that each Grid is uniquely owned by one Simulation instance, preventing accidental sharing of grid data.

The main function demonstrates the usage of each of these classes, showing how they can be applied in different scientific computing scenarios. This code provides a solid foundation for understanding memory management techniques in C++ within the context of scientific simulations.

Related

Previous Page | Course Schedule | Course Content