想象一下,我们将一个对象传递给一个函数,并希望将语义移动到其各个成员中。选择哪个选项:在每个成员上调用std::move
或移动整个对象(多次),然后将其成员作为rvalues访问?
Foo::Foo(Object object)
// this way?
: member1(std::move(object.member1)), member2(std::move(object.member2)) {}
// or this way?
: member2(std::move(object).member2), member2(std::move(object).member2) {}
更具体地说,请考虑以下示例。有一个下载器类,它接受连接参数作为对象。我想移动 - 将其成员分配给下载程序的成员,所以我正在执行以下操作:
class ConnectionParameters
{
public:
ConnectionParameters(string server, string login, string password, unsigned short port, unsigned int connectionLimit, unsigned long long speedLimit)
: server(move(server))
, login(move(login))
, password(move(password))
, port(port)
, connectionLimit(connectionLimit)
, speedLimit(speedLimit) {}
ConnectionParameters(const ConnectionParameters &) = delete; // disable copy constructor
ConnectionParameters(ConnectionParameters &&) = default; // default move constructor
const string & getServer() const & { return this->server; }
string && getServer() && { return move(this->server); }
const string & getLogin() const & { return this->login; }
string && getLogin() && { return move(this->login); }
const string & getPassword() const & { return this->password; }
string && getPassword() && { return move(this->password); }
unsigned short getPort() const { return this->port; }
unsigned int getConnectionLimit() const { return this->connectionLimit; }
unsigned long long getSpeedLimit() const { return this->speedLimit; }
private:
string server, login, password;
unsigned short port;
unsigned int connectionLimit;
unsigned long long speedLimit;
};
class Downloader
{
public:
Downloader(ConnectionParameters connectionParameters, string downloadDirectory, unsigned long long diskSpaceMinimum)
: server(move(connectionParameters).getServer()) // 1st move
, login(move(connectionParameters).getLogin()) // 2nd move!
, password(move(connectionParameters).getPassword()) // 3rd move!
, port(connectionParameters.getPort())
, connectionLimit(connectionParameters.getConnectionLimit())
, speedLimit(connectionParameters.getSpeedLimit())
, downloadDirectory(move(downloadDirectory))
, diskSpaceMinimum(diskSpaceMinimum) {}
private:
string server, login, password;
unsigned short port;
unsigned int connectionLimit;
unsigned long long speedLimit;
string downloadDirectory;
unsigned long long diskSpaceMinimum;
};
我不喜欢这种方法是在同一个std::move
对象上多次调用connectionParameters
。虽然它有效但它可能违反了移动语义的原则(移动后不能使用该对象)。
另一种方法是单独移动成员:
struct ConnectionParameters
{
string server, login, password;
unsigned short port;
unsigned int connectionLimit;
unsigned long long speedLimit;
ConnectionParameters(string server, string login, string password, unsigned short port, unsigned int connectionLimit, unsigned long long speedLimit)
: server(move(server))
, login(move(login))
, password(move(password))
, port(port)
, connectionLimit(connectionLimit)
, speedLimit(speedLimit) {}
ConnectionParameters(const ConnectionParameters &) = delete; // disable copy constructor
ConnectionParameters(ConnectionParameters &&) = default; // default move constructor
};
class Downloader
{
public:
Downloader(ConnectionParameters connectionParameters, string downloadDirectory, unsigned long long diskSpaceMinimum)
: server(move(connectionParameters.server))
, login(move(connectionParameters.login))
, password(move(connectionParameters.password))
, port(connectionParameters.port)
, connectionLimit(connectionParameters.connectionLimit)
, speedLimit(connectionParameters.speedLimit)
, downloadDirectory(move(downloadDirectory))
, diskSpaceMinimum(diskSpaceMinimum) {}
private:
string server, login, password;
unsigned short port;
unsigned int connectionLimit;
unsigned long long speedLimit;
string downloadDirectory;
unsigned long long diskSpaceMinimum;
};
我不喜欢的是ConnectionParameters
结构的成员直接暴露(否则,Downloader
将无法移动它们。)
这样做的正确方法是什么?