Tratterei la classe come non copiabile nella firma se la copia è sufficientemente costosa. Semanticamente le cose sono riproducibili solo se vuoi che siano, e una copia costosa è un buon motivo per decidere "no, non copiabile".
La possibilità di copiare qualcosa non significa che sia necessario implementarlo in un tipo che è possibile copiare. L'implementatore di quel tipo arriva a decidere se dovrebbe essere semanticamente copiabile.
Non chiamerei l'operazione che ha prodotto una copia "copia" costosa, ma piuttosto "clona" o "duplicata".
Per un modo si potrebbe fare questo:
#include <utility>
template<typename T>
struct DoCopy {
T const& t;
DoCopy(T const& t_):t(t_) {}
};
template<typename T>
DoCopy<T> do_copy(T const& t) {
return t;
}
struct Foo {
struct ExpensiveToCopy {
int _[100000000];
};
ExpensiveToCopy* data;
Foo():data(new ExpensiveToCopy()) {}
~Foo(){ delete data; }
Foo(Foo&& o):data(o.data) { o.data = nullptr; }
Foo& operator=(Foo&& o) { data=o.data; o.data=nullptr; return *this; }
Foo& operator=(DoCopy<Foo> o) {
delete data;
if (o.t.data) {
data=new ExpensiveToCopy(*o.t.data);
} else {
data=new ExpensiveToCopy();
}
return *this;
}
Foo(DoCopy<Foo> cp):data(cp.t.data?new ExpensiveToCopy(*cp.t.data):new ExpensiveToCopy()) {};
};
int main() {
Foo one;
// Foo two = one; // illegal
Foo three = std::move(one); // legal
Foo four;
Foo five = do_copy(three);
four = std::move(three);
five = do_copy(four);
}
Questo è in qualche modo simile ai modi si potrebbe avere scritto std::move
come la semantica prima della esistenza di riferimenti rvalue, con aspetti negativi simili a tali tecniche, vale a dire che il linguaggio stesso non ha idea di cosa siano gli shenanigans.
ha il vantaggio che la sintassi di cui sopra do_copy
è simile alla sintassi di std::move
, e consente di utilizzare le espressioni tradizionali senza dover creare istanze di banali Foo
poi costruire una copia di un'altra variabile, ecc
Se le situazioni in cui vogliamo trattarlo come copiabili sono comuni (se si vuole evitare), scriverò un copy-wrapper attorno alla classe che conosce il metodo duplicate
.
Immagino che il problema con una funzione membro 'copia' sia che interrompe tutto il codice modello che utilizza l'operatore di assegnazione. – Pubby