Im confusd sull'uso di std::move
nei costruttori di classi.
Voglio passare un valore a una classe e controllare nel costruttore se viene passato un valore valido. Se non viene generata un'eccezione.
Prima di solito passavo il valore con riferimento const:
#include <string>
class Foo {
public:
Foo(const std::string& value)
:m_value{ value }
{
if (value == "Foo") {
throw std::invalid_argument("Invalid");
}
}
private:
std::string m_value;
};
Ora leggo in c ++ moderno è meglio passare per valore e spostare il valore passato nella variabile di classe:
#include <string>
class Foo {
public:
Foo(std::string value)
:m_value{ std::move (value) }
{
// Now m_value must be used because value is empty if reference
//if(value == "Foo") -> Desaster value is moved away = empty
if (m_value == "Foo") {
throw std::invalid_argument("Invalid");
}
}
private:
std::string m_value;
};
Fin qui tutto bene posso solo fare riferimento alla variabile di classe per eseguire il mio controllo degli errori. Ora ho iniziato a modernizzare un codebass che ha una gerarchia di classi se un valore è già definito nella classe base. La classe bambino esegue fondamentalmente controlli aggiuntivi sulla variabile e sui lanci.
Ecco un esempio semplificato:
#include <string>
class Bar {
public:
Bar(std::string value)
:m_value{std::move(value))}
{
// value is "empty" here because its moved into m_value
if (m_value == "Foo") {
throw std::invalid_argument("Invalid");
}
}
std::string get_value() const { return m_value; }
void set_value(const std::string& value)
{
m_value = value;
}
private:
std::string m_value;
};
// Version 1
// We have to ask several times the base class to get the compare value
class Foo : public Bar {
public:
Foo(std::string value)
:Bar{ std::move(value) }
{
if (get_value() == "BAR" ||
get_value() == "Bar" || // perform several checks here
get_value() == "bar") {
throw std::invalid_argument("Invalid");
}
}
};
// Version 2
// We need to make a copy to check. Doesn't this ruin the purpose of
// std::move by saving a copy??
class Foo : public Bar {
public:
Foo(std::string value)
:Bar{ std::move(value) }
{
auto check_value = get_value();
if (check_value == "BAR" ||
check_value == "Bar" || // perform several checks here
check_value == "bar") {
throw std::invalid_argument("Invalid");
}
}
};
// Version 3
// doesn't work except we provide in the base class a default constructor
class Foo : public Bar {
public:
Foo(std::string value)
//Error here we need to provide a default constructor
{
if (value == "BAR" ||
value == "Bar" || // perform several checks here
value == "bar") {
throw std::invalid_argument("Invalid");
}
set_value(std::move(value));
}
};
Quindi la mia domanda è, quale approccio è il migliore. O come può essere gestito meglio?