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:
- Reads a list of integer sensor readings from standard input into a
SensorBuffer. - Reads a list of operations (
ScaleOperationorClampOperation). - Copies and moves
SensorBufferobjects to exercise copy/move constructors and assignment. - Applies all operations in order to a working buffer using polymorphism.
- Prints the final readings.
3. Input Format
From stdin:
- An integer $N$: the number of sensor readings.
- $N$ integers: the readings.
- An integer $O$: the number of operations.
- Then $O$ operations, each described by:
- A character indicating the type:
'S'for scale,'C'for clamp.
- Parameters:
- For
'S': one integerfactor. - For
'C': two integersminValueandmaxValue.
- For
- A character indicating the type:
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;
}
