Logo C++ Online Judge

C++

时间限制:1 s 空间限制:512 MB
TA:
统计

1. Background

We want to process a sequence of integer sensor readings with a configurable pipeline of operations. For example:

  • multiply all readings by a factor;
  • clamp all readings into a given range.

clamp的意思是一个值如果小于最小值则设为最小值,大于最大值则设为最大值

We store the readings in a SensorBuffer object. This class owns a dynamically allocated array of int, managed by std::unique_ptr<int[]>;

We also define an abstract base class Operation:

  • it has a pure virtual method apply(SensorBuffer&) const;
  • two concrete derived classes implement different operations:
    • ScaleOperation,
    • ClampOperation.

At runtime, we keep a list of std::unique_ptr<Operation> and apply them polymorphically to a SensorBuffer.

2. Program Behavior

The program:

  1. Reads a list of integer sensor readings from standard input into a SensorBuffer.
  2. Reads a list of operations (ScaleOperation or ClampOperation).
  3. Copies and moves SensorBuffer objects to exercise copy/move constructors and assignment.
  4. Applies all operations in order to a working buffer using polymorphism.
  5. Prints the final readings.

3. Input Format

From stdin:

  1. An integer $N$: the number of sensor readings.
  2. $N$ integers: the readings.
  3. An integer $O$: the number of operations.
  4. Then $O$ operations, each described by:
    • A character indicating the type:
      • 'S' for scale,
      • 'C' for clamp.
    • Parameters:
      • For 'S': one integer factor.
      • For 'C': two integers minValue and maxValue.

Example (not tied to any specific expected output):

5
10 20 30 -5 100
2
S 2
C 0 50

4. Output Format

Print the final readings as a single line of $N$ integers separated by single spaces, then a newline. No extra text should be printed.

Example:

20 40 50 0 50

5. Your Task

Fill in all places marked with TODO in the code below.

You are not allowed to change other places in the code.

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <cstddef>
#include <cassert>

class SensorBuffer {
private:
    std::unique_ptr<int[]> data;
    std::size_t size;

public:
    // Counters to track copy/move usage
    static int copyCtorCount;
    static int moveCtorCount;
    static int copyAssignCount;
    static int moveAssignCount;

    // Default constructor: empty buffer
    SensorBuffer()
        : data(nullptr), size(0) {}

    // Construct buffer of given size, initialized to 0
    explicit SensorBuffer(std::size_t n)
        : data(nullptr), size(n) {
        if (size > 0) {
            data = std::unique_ptr<int[]>(new int[size]);
            for (std::size_t i = 0; i < size; ++i) {
                data[i] = 0;
            }
        }
    }

    // Destructor: default is fine because unique_ptr handles deletion
    ~SensorBuffer() = default;

    // Copy constructor: deep copy
    SensorBuffer(const SensorBuffer& other)
        : data(nullptr), size(0) {
        ++copyCtorCount;
        /* TODO SB1: deep copy from other into *this */
    }

    // Move constructor: steal the resources
    SensorBuffer(SensorBuffer&& other) noexcept
        : data(nullptr), size(0) {
        ++moveCtorCount;
        /* TODO SB2: steal other's resources into *this */
    }

    // Swap function: exchange internal state with another SensorBuffer
    void swap(SensorBuffer& other) noexcept {
        using std::swap;
        swap(data, other.data);
        swap(size, other.size);
    }

    SensorBuffer& operator=(const SensorBuffer& other) {
        if (this != &other) {
            ++copyAssignCount;
            SensorBuffer tmp(other); // uses copy constructor
            swap(tmp);
        }
        return *this;
    }

    SensorBuffer& operator=(SensorBuffer&& other) noexcept {
        if (this != &other) {
            ++moveAssignCount;
            swap(other);
        }
        return *this;
    }

    std::size_t getSize() const {
        return size;
    }

    int& operator[](std::size_t index) {
        return data[index];
    }

    const int& operator[](std::size_t index) const {
        return data[index];
    }
};

// static counter definitions
int SensorBuffer::copyCtorCount   = 0;
int SensorBuffer::moveCtorCount   = 0;
int SensorBuffer::copyAssignCount = 0;
int SensorBuffer::moveAssignCount = 0;

// Abstract base class for all operations
class Operation {
public:
    // Virtual destructor to allow deleting through base pointer
    virtual ~Operation() = default;

    // Apply this operation to the given sensor buffer
    virtual void apply(SensorBuffer& buffer) const = 0;
};

// Multiply each sensor reading by a factor
class ScaleOperation : public Operation {
private:
    int factor;

public:
    explicit ScaleOperation(int factor)
        : factor(factor) {}

    void apply(SensorBuffer& buffer) const override {
        /* TODO OP1: multiply each element in buffer by factor */
    }
};

// Clamp each sensor reading into [minValue, maxValue]
class ClampOperation : public Operation {
private:
    int minValue;
    int maxValue;

public:
    ClampOperation(int minValue, int maxValue)
        : minValue(minValue), maxValue(maxValue) {}

    void apply(SensorBuffer& buffer) const override {
        /* TODO OP2: clamp each element in buffer into [minValue, maxValue] */
    }
};

// Apply all operations in order to the buffer, using polymorphism
void applyAll(const std::vector<std::unique_ptr<Operation>>& ops,
              SensorBuffer& buffer) {
    for (const auto& op : ops) {
        /* TODO AP1: call the virtual apply function through op */
    }
}

int main() {
    std::size_t N;
    if (!(std::cin >> N)) {
        return 0;
    }

    SensorBuffer original(N);
    for (std::size_t i = 0; i < N; ++i) {
        int value;
        std::cin >> value;
        original[i] = value;
    }

    int O;
    std::cin >> O;

    std::vector<std::unique_ptr<Operation>> ops;
    ops.reserve(static_cast<std::size_t>(O));

    // Read operations
    for (int k = 0; k < O; ++k) {
        char type;
        std::cin >> type;
        if (type == 'S') {
            int factor;
            std::cin >> factor;
            // Create a ScaleOperation and store it as a unique_ptr<Operation>
            std::unique_ptr<Operation> op = /* TODO MAIN1: create ScaleOperation */;
            ops.push_back(/* TODO MAIN2: move op into vector */);
        } else if (type == 'C') {
            int minVal, maxVal;
            std::cin >> minVal >> maxVal;
            // Create a ClampOperation and store it as a unique_ptr<Operation>
            std::unique_ptr<Operation> op = /* TODO MAIN3: create ClampOperation */;
            ops.push_back(/* TODO MAIN4: move op into vector */);
        }
    }

    // Make a copy of the original buffer (tests copy constructor)
    SensorBuffer working = /* TODO MAIN5: copy-construct from original */;

    // Move-construct a buffer from the working copy (tests move constructor)
    SensorBuffer temp = /* TODO MAIN6: move-construct from working */;

    // Apply all operations to temp (tests polymorphism through unique_ptr)
    /* TODO MAIN7: call applyAll with ops and temp */;

    // Move the result back into working (tests move assignment)
    working = /* TODO MAIN8: move-assign from temp */;

    // Assertions to ensure no extra copy / move operations occurred.
    // Expected:
    // - 1 copy construction (working from original)
    // - 1 move construction (temp from working)
    // - 0 copy assignments
    // - 1 move assignment (working from temp)
    assert(SensorBuffer::copyCtorCount   == 1);
    assert(SensorBuffer::moveCtorCount   == 1);
    assert(SensorBuffer::copyAssignCount == 0);
    assert(SensorBuffer::moveAssignCount == 1);

    // Print final readings
    for (std::size_t i = 0; i < working.getSize(); ++i) {
        std::cout << working[i];
        if (i + 1 < working.getSize()) {
            std::cout << ' ';
        }
    }
    std::cout << '\n';

    return 0;
}