Esercizi Regole 3-5 C++
Codegrind Team•Jul 12 2024
Ecco degli esercizi con soluzione per praticare l’utilizzo delle Rule of Three e Rule of Five in C++.
Rule of Three
Esercizio 1: Implementazione della Rule of Three
Creare una classe con costruttore di copia, operatore di assegnazione di copia e distruttore.
#include <iostream>
class MyClass {
private:
int* data;
public:
// Costruttore
MyClass(int value) : data(new int(value)) {}
// Costruttore di copia
MyClass(const MyClass& other) : data(new int(*other.data)) {
std::cout << "Costruttore di copia chiamato" << std::endl;
}
// Operatore di assegnazione di copia
MyClass& operator=(const MyClass& other) {
if (this == &other) return *this;
*data = *other.data;
std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
return *this;
}
// Distruttore
~MyClass() {
delete data;
std::cout << "Distruttore chiamato" << std::endl;
}
void print() const {
std::cout << "Valore: " << *data << std::endl;
}
};
int main() {
MyClass obj1(10);
MyClass obj2 = obj1; // Costruttore di copia chiamato
obj2 = obj1; // Operatore di assegnazione di copia chiamato
obj1.print();
obj2.print();
return 0;
}
Esercizio 2: Profondo contro copia superficiale
Implementare una copia superficiale e osservare i problemi di gestione della memoria.
#include <iostream>
class MyClass {
private:
int* data;
public:
MyClass(int value) : data(new int(value)) {}
// Costruttore di copia (superficiale)
MyClass(const MyClass& other) : data(other.data) {
std::cout << "Costruttore di copia superficiale chiamato" << std::endl;
}
// Distruttore
~MyClass() {
delete data;
std::cout << "Distruttore chiamato" << std::endl;
}
void print() const {
std::cout << "Valore: " << *data << std::endl;
}
};
int main() {
MyClass obj1(10);
MyClass obj2 = obj1; // Costruttore di copia superficiale chiamato
obj1.print();
obj2.print();
return 0;
}
Rule of Five
Esercizio 3: Implementazione della Rule of Five
Creare una classe con costruttore di copia, operatore di assegnazione di copia, costruttore di spostamento, operatore di assegnazione di spostamento e distruttore.
#include <iostream>
class MyClass {
private:
int* data;
public:
// Costruttore
MyClass(int value) : data(new int(value)) {}
// Costruttore di copia
MyClass(const MyClass& other) : data(new int(*other.data)) {
std::cout << "Costruttore di copia chiamato" << std::endl;
}
// Operatore di assegnazione di copia
MyClass& operator=(const MyClass& other) {
if (this == &other) return *this;
*data = *other.data;
std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
return *this;
}
// Costruttore di spostamento
MyClass(MyClass&& other) noexcept : data(other.data) {
other.data = nullptr;
std::cout << "Costruttore di spostamento chiamato" << std::endl;
}
// Operatore di assegnazione di spostamento
MyClass& operator=(MyClass&& other) noexcept {
if (this == &other) return *this;
delete data;
data = other.data;
other.data = nullptr;
std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
return *this;
}
// Distruttore
~MyClass() {
delete data;
std::cout << "Distruttore chiamato" << std::endl;
}
void print() const {
if (data)
std::cout << "Valore: " << *data << std::endl;
else
std::cout << "Nessun dato" << std::endl;
}
};
int main() {
MyClass obj1(10);
MyClass obj2 = std::move(obj1); // Costruttore di spostamento chiamato
obj2.print();
obj1.print();
return 0;
}
Esercizio 4: Utilizzo di std::move con la Rule of Five
Creare una classe con la Rule of Five e utilizzare `std::move` per spostare un oggetto.
#include <iostream>
#include <utility> // Per std::move
class MyClass {
private:
int* data;
public:
MyClass(int value) : data(new int(value)) {}
MyClass(const MyClass& other) : data(new int(*other.data)) {
std::cout << "Costruttore di copia chiamato" << std::endl;
}
MyClass& operator=(const MyClass& other) {
if (this == &other) return *this;
*data = *other.data;
std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
return *this;
}
MyClass(MyClass&& other) noexcept : data(other.data) {
other.data = nullptr;
std::cout << "Costruttore di spostamento chiamato" << std::endl;
}
MyClass& operator=(MyClass&& other) noexcept {
if (this == &other) return *this;
delete data;
data = other.data;
other.data = nullptr;
std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
return *this;
}
~MyClass() {
delete data;
std::cout << "Distruttore chiamato" << std::endl;
}
void print() const {
if (data)
std::cout << "Valore: " << *data << std::endl;
else
std::cout << "Nessun dato" << std::endl;
}
};
int main() {
MyClass obj1(10);
MyClass obj2 = std::move(obj1); // Costruttore di spostamento chiamato
obj2.print();
obj1.print();
return 0;
}
Esercizio 5: Creazione di un vettore di oggetti con la Rule of Five
Creare una classe con la Rule of Five e utilizzare un vettore per gestire più oggetti.
#include <iostream>
#include <vector>
#include <utility>
class MyClass {
private:
int* data;
public:
MyClass(int value) : data(new int(value)) {}
MyClass(const MyClass& other) : data(new int(*other.data)) {
std::cout << "Costruttore di copia chiamato" << std::endl;
}
MyClass& operator=(const MyClass& other) {
if (this == &other) return *this;
*data = *other.data;
std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
return *this;
}
MyClass(MyClass&& other) noexcept : data(other.data) {
other.data = nullptr;
std::cout << "Costruttore di spostamento chiamato" << std::endl;
}
MyClass& operator=(MyClass&& other)
noexcept {
if (this == &other) return *this;
delete data;
data = other.data;
other.data = nullptr;
std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
return *this;
}
~MyClass() {
delete data;
std::cout << "Distruttore chiamato" << std::endl;
}
void print() const {
if (data)
std::cout << "Valore: " << *data << std::endl;
else
std::cout << "Nessun dato" << std::endl;
}
};
int main() {
std::vector<MyClass> vec;
vec.push_back(MyClass(10));
vec.push_back(MyClass(20));
vec.push_back(MyClass(30));
for (const auto& obj : vec) {
obj.print();
}
return 0;
}
Esercizio 6: Gestione della memoria con la Rule of Five
Creare una classe che gestisce un array dinamico e implementare la Rule of Five.
#include <iostream>
#include <utility> // Per std::move
class MyArray {
private:
int* data;
size_t size;
public:
MyArray(size_t size) : data(new int[size]), size(size) {
for (size_t i = 0; i < size; ++i) {
data[i] = static_cast<int>(i);
}
}
MyArray(const MyArray& other) : data(new int[other.size]), size(other.size) {
std::copy(other.data, other.data + size, data);
std::cout << "Costruttore di copia chiamato" << std::endl;
}
MyArray& operator=(const MyArray& other) {
if (this == &other) return *this;
delete[] data;
size = other.size;
data = new int[size];
std::copy(other.data, other.data + size, data);
std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
return *this;
}
MyArray(MyArray&& other) noexcept : data(other.data), size(other.size) {
other.data = nullptr;
other.size = 0;
std::cout << "Costruttore di spostamento chiamato" << std::endl;
}
MyArray& operator=(MyArray&& other) noexcept {
if (this == &other) return *this;
delete[] data;
data = other.data;
size = other.size;
other.data = nullptr;
other.size = 0;
std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
return *this;
}
~MyArray() {
delete[] data;
std::cout << "Distruttore chiamato" << std::endl;
}
void print() const {
for (size_t i = 0; i < size; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
};
int main() {
MyArray arr1(10);
MyArray arr2 = std::move(arr1); // Costruttore di spostamento chiamato
arr2.print();
arr1.print(); // Non stampa nulla, arr1 è stato spostato
return 0;
}
Esercizio 7: Creazione di una classe gestita con std::unique_ptr
Creare una classe che utilizza `std::unique_ptr` per gestire la memoria e implementare la Rule of Five.
#include <iostream>
#include <memory>
class MyClass {
private:
std::unique_ptr<int> data;
public:
MyClass(int value) : data(std::make_unique<int>(value)) {}
MyClass(const MyClass& other) : data(std::make_unique<int>(*other.data)) {
std::cout << "Costruttore di copia chiamato" << std::endl;
}
MyClass& operator=(const MyClass& other) {
if (this == &other) return *this;
data = std::make_unique<int>(*other.data);
std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
return *this;
}
MyClass(MyClass&& other) noexcept : data(std::move(other.data)) {
std::cout << "Costruttore di spostamento chiamato" << std::endl;
}
MyClass& operator=(MyClass&& other) noexcept {
if (this == &other) return *this;
data = std::move(other.data);
std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
return *this;
}
void print() const {
if (data)
std::cout << "Valore: " << *data << std::endl;
else
std::cout << "Nessun dato" << std::endl;
}
};
int main() {
MyClass obj1(10);
MyClass obj2 = std::move(obj1); // Costruttore di spostamento chiamato
obj2.print();
obj1.print(); // Non stampa nulla, obj1 è stato spostato
return 0;
}
Esercizio 8: Creazione di una classe gestita con std::shared_ptr
Creare una classe che utilizza `std::shared_ptr` per gestire la memoria e implementare la Rule of Five.
#include <iostream>
#include <memory>
class MyClass {
private:
std::shared_ptr<int> data;
public:
MyClass(int value) : data(std::make_shared<int>(value)) {}
MyClass(const MyClass& other) : data(other.data) {
std::cout << "Costruttore di copia chiamato" << std::endl;
}
MyClass& operator=(const MyClass& other) {
if (this == &other) return *this;
data = other.data;
std::cout << "Operatore di assegnazione di copia chiamato" << std::endl;
return *this;
}
MyClass(MyClass&& other) noexcept : data(std::move(other.data)) {
std::cout << "Costruttore di spostamento chiamato" << std::endl;
}
MyClass& operator=(MyClass&& other) noexcept {
if (this == &other) return *this;
data = std::move(other.data);
std::cout << "Operatore di assegnazione di spostamento chiamato" << std::endl;
return *this;
}
void print() const {
if (data)
std::cout << "Valore: " << *data << std::endl;
else
std::cout << "Nessun dato" << std::endl;
}
};
int main() {
MyClass obj1(10);
MyClass obj2 = std::move(obj1); // Costruttore di spostamento chiamato
obj2.print();
obj1.print(); // Non stampa nulla, obj1 è stato spostato
return 0;
}