argomenti Nome il cui scopo è quello di essere spostato-da in qualche modo distintivo, almeno nella attuazione del costruttore
A::A(std::string val_moved_from):
_val(std::move(val_moved_from))
{
std::cout << val_moved_from << std::endl; // Bug, but obvious
}
poi passare da loro il più presto possibile (nell'elenco costruzione, dicono) .
Se si dispone di un elenco di costruzione così lungo è possibile perdere due usi di val_moved_from
in esso, questo non aiuta.
Un'alternativa sarebbe scrivere una proposta per risolvere questo problema. Supponi, estendi C++ in modo che i tipi o gli ambiti delle variabili locali possano essere modificati dalle operazioni su di essi, quindi std::safe_move(X)
si sposta entrambi da X
e contrassegna X
come variabile scaduta, non più valida da utilizzare, per il resto del suo ambito. Elaborare cosa fare quando una variabile è scaduta per metà (scaduta in un ramo, ma non in un altro) è una domanda interessante.
Dato che è folle, possiamo invece attaccarlo come un problema di libreria. In una certa misura, possiamo simulare questo tipo di trucchi (una variabile il cui tipo cambia) in fase di esecuzione. Si tratta di greggio, ma dà l'idea:
template<typename T>
struct read_once : std::tr2::optional<T> {
template<typename U, typename=typename std::enable_if<std::is_convertible<U&&, T>::value>::type>
read_once(U&& u):std::tr2::optional<T>(std::forward<U>(u)) {}
T move() && {
Assert(*this);
T retval = std::move(**this);
*this = std::tr2::none_t;
return retval;
}
// block operator*?
};
cioè, scrivere tipo lineare che può essere letto solo da via move
, e dopo che il tempo leggendo Assert
s o tiri.
Quindi modificare il vostro costruttore:
A::A(read_once<std::string> val):
_val(val.move())
{
std::cout << val << std::endl; // does not compile
std::cout << val.move() << std::endl; // compiles, but asserts or throws
}
con costruttori di inoltro, è possibile esporre un'interfaccia meno ridicola senza read_once
tipi, poi in avanti i tuoi costruttori al "sicuro" (possibilmente private
) versioni con read_once<>
wrapper intorno gli argomenti.
Se i test coprono tutte le percorsi di codice, si otterrà bel Assert
s invece di vuote std::string
s, anche se si va e più di una volta move
dai vostri read_once
variabili.
"fatto la _move_ a C++ 11" molto bello –
"Cosa posso fare per ridurre le possibilità di sbagliare?" Non tanto. Lasciare oggetti in stati validi ma strani è ridicolo, ed è una delle ragioni per cui la semantica del movimento di C++ 11 è stupida. –
Cosa c'è di sbagliato nell'usare _val all'interno del corpo del costruttore? – Thorsten