假设我们有一个 Person 类,代码如下:
class Person {
public:
Person(const std::string &first_name, const std::string &last_name)
: first_name_(first_name), last_name_(last_name) {}
private:
std::string first_name_;
std::string last_name_;
};这段代码看起来似乎没有问题,但实际上存在潜在的性能问题。如果像这样构造 Person 对象:
int main() {
Person person("klare", "neroll");
}由于传递的实参是 const char * 类型,与构造函数的形参类型 const std::string & 不符,因此会编译器构造一个临时的 string 对象,并将其绑定到形参上。在这个过程中,实参字符串会被拷贝到临时对象中,这是第一次拷贝。
在构造函数的成员初始化列表中,: first_name_(first_name), last_name_(last_name) 会通过拷贝构造函数构造 Person 的两个成员,字符串再次发生拷贝,这是第二次拷贝。
可以看到,在 person 对象的构造过程中,两个参数各被拷贝了两次。在理想情况下,每个实参应该只被拷贝一次。因此,这里存在多余的拷贝。
有没有办法消除多余的拷贝呢?当然可以,再加一个构造函数,用 const char * 作为参数类型就可以了:
class Person {
public:
Person(const std::string &first_name, const std::string &last_name)
: first_name_(first_name), last_name_(last_name) {}
Person(const char *first_name, const char *last_name)
: first_name_(first_name), last_name_(last_name) {}
private:
std::string first_name_;
std::string last_name_;
};这样,当使用两个字符串字面量构造 Person 对象时,会调用第二个构造函数,参数只会在成员初始化列表中被拷贝一次,不会有多余的拷贝。
等等,如果一个参数是 std::stirng,另一个参数是 const char *,会发生什么?
int main() {
std::string first_name = "klare";
Person person(first_name, "neroll");
}这里会匹配第一个构造函数,由于第二个实参类型是 const char *,还是构造了临时对象,造成多余拷贝。
怎么解决?难道要这么写:
class Person {
public:
Person(const std::string &first_name, const std::string &last_name)
: first_name_(first_name), last_name_(last_name) {}
Person(const char *first_name, const char *last_name)
: first_name_(first_name), last_name_(last_name) {}
Person(const std::string &first_name, const char *last_name)
: first_name_(first_name), last_name_(last_name) {}
Person(const char *first_name, const std::string &last_name)
: first_name_(first_name), last_name_(last_name) {}
private:
std::string first_name_;
std::string last_name_;
};这也太可怕了,仅仅两个参数就要写四个构造函数,难道就没有更优雅的方法?
当然有,这就是值传递并移动(pass by value and use std::move)方法。按照这个方法,只需要这么写:
class Person {
public:
Person(std::string first_name, std::string last_name)
: first_name_(std::move(first_name)), last_name_(std::move(last_name)) {}
private:
std::string first_name_;
std::string last_name_;
};一个构造函数,统一所有情况。在所有情况下,这种写法最多只会有一次拷贝。下面来看看不同情况下都发生了什么。
当两个实参都是 std::string 时:
int main() {
std::string first_name = "klare";
std::string last_name = "neroll";
Person person(first_name, last_name);
}构造函数的参数会通过 std::string 的拷贝构造函数构造,此时字符串被拷贝一次。
在成员初始化列表中,: first_name_(std::move(first_name)), last_name_(std::move(last_name)) 通过移动构造函数初始化 person 对象的两个成员,此时不发生拷贝。因此总共只发生一次拷贝。
当两个参数都是 const char * 时,或者一个 std::string,一个 const char * 时,情况类似,每个参数都只被拷贝一次。
这种写法的优势还不仅于此,它还可以做到零拷贝。例如下面这种情况:
int main() {
std::string first_name = "klare";
std::string last_name = "neroll";
Person person(std::move(first_name), std::move(last_name));
}在这种情况下,构造函数的参数会通过移动构造函数构造,不发生拷贝,在成员初始化列表中,再次通过移动构造函数初始化两个成员,同样也不发生拷贝。main 函数中的字符串通过两次 std::move,最终被移动到了 person 的成员中,整个过程不发生任何拷贝。
Pass by value and use std::move 不仅仅适用于参数为 std::string 的情况。在参数类型可拷贝、可移动,且移动的代价小于拷贝的代价时,就可以使用这种写法。在大部分场景下,这种写法都适用。
Pass by value and use std::move 是一个良好的实践,目前它已经被集成到了 clang-tidy 中,只要打开相应选项,clang-tidy 就会对能够优化的地方发出警告。在 C++ 代码中,推荐在构造函数中使用这种写法,减少不必要的拷贝,提升性能。这不是过早优化,而是良好的实践范例。
13 条评论
华纳公司官方开户渠道?(183-8890-9465)-薇-STS5099【6011643】
如何通过官方渠道申请华纳公司账户?(183-8890-9465)-薇-STS5099【6011643】
华纳总公司官方开户指南?(183-8890-9465)-薇-STS5099【6011643】
华纳公司官方开户所需材料?(183-8890-9465)-薇-STS5099【6011643】
华纳官方开户流程?(183-8890-9465)-薇-STS5099【6011643】
华纳公司官方开户申请步骤?(183-8890-9465)-薇-STS5099【6011643】
华纳官方开户指南?(183-8890-9465)-薇-STS5099【6011643】
华纳总公司官方开户?(183-8890-9465)-薇-STS5099【6011643】
华纳公司官方开户所需材料?(183-8890-9465)-薇-STS5099【6011643】
华纳官方开户申请流程?(183-8890-9465)-薇-STS5099【6011643】
华纳公司官方开户渠道?(183-8890-9465)-薇-STS5099【6011643】
如何通过官方渠道申请华纳公司账户?(183-8890-9465)-薇-STS5099【6011643】
华纳总公司官方开户指南?(183-8890-9465)-薇-STS5099【6011643】
华纳公司官方开户所需材料?(183-8890-9465)-薇-STS5099【6011643】
华纳官方开户流程?(183-8890-9465)-薇-STS5099【6011643】
华纳公司官方开户申请步骤?(183-8890-9465)-薇-STS5099【6011643】
华纳官方开户指南?(183-8890-9465)-薇-STS5099【6011643】
华纳总公司官方开户?(183-8890-9465)-薇-STS5099【6011643】
华纳公司官方开户所需材料?(183-8890-9465)-薇-STS5099【6011643】
华纳官方开户申请流程?(183-8890-9465)-薇-STS5099【6011643】
寻找华纳圣淘沙公司开户代理(183-8890-9465薇-STS5099】
华纳圣淘沙官方合作开户渠道(183-8890-9465薇-STS5099】
华纳圣淘沙公司开户代理服务(183-8890-9465薇-STS5099】
华纳圣淘沙公司开户咨询热线(183-8890-9465薇-STS5099】
联系客服了解华纳圣淘沙开户
(183-8890-9465薇-STS5099】
华纳圣淘沙公司开户专属顾问
(183-8890-9465薇-STS5099】
华纳圣淘沙开户步骤详解(183-8890-9465—?薇-STS5099【6011643】
华纳圣淘沙公司开户流程全解析(183-8890-9465—?薇-STS5099【6011643】
华纳圣淘沙公司账户注册指南(183-8890-9465—?薇-STS5099【6011643】
新手如何开通华纳圣淘沙公司账户(183-8890-9465—?薇-STS5099【6011643】
华纳圣淘沙企业开户标准流程(183-8890-9465—?薇-STS5099【6011643】
华纳圣淘沙公司开户:从零到一(183-8890-9465—?薇-STS5099【6011643】
官方指南:华纳圣淘沙公司开户流程(183-8890-9465—?薇-STS5099【6011643】
华纳圣淘沙公司开户流程说明书(183-8890-9465—?薇-STS5099【6011643】
东方明珠客服开户联系方式【182-8836-2750—】?μ- cxs20250806
东方明珠客服电话联系方式【182-8836-2750—】?- cxs20250806】
东方明珠开户流程【182-8836-2750—】?薇- cxs20250806】
东方明珠客服怎么联系【182-8836-2750—】?薇- cxs20250806】
果博东方客服开户联系方式【182-8836-2750—】?薇- cxs20250806】
果博东方公司客服电话联系方式【182-8836-2750—】?薇- cxs20250806】
果博东方开户流程【182-8836-2750—】?薇- cxs20250806】
果博东方客服怎么联系【182-8836-2750—】?薇- cxs20250806】
果博东方客服开户联系方式【182-8836-2750—】?薇- cxs20250806】
果博东方公司客服电话联系方式【182-8836-2750—】?薇- cxs20250806】
果博东方开户流程【182-8836-2750—】?薇- cxs20250806】
果博东方客服怎么联系【182-8836-2750—】?薇- cxs20250806】
新盛客服电话是多少?(?183-8890-9465—《?薇-STS5099】【
新盛开户专线联系方式?(?183-8890--9465—《?薇-STS5099】【?扣6011643??】
新盛客服开户电话全攻略,让娱乐更顺畅!(?183-8890--9465—《?薇-STS5099】客服开户流程,华纳新盛客服开户流程图(?183-8890--9465—《?薇-STS5099】
华纳东方明珠客服电话是多少?(??155--8729--1507?《?薇-STS5099】【?扣6011643?】
华纳东方明珠开户专线联系方式?(??155--8729--1507?《?薇-STS5099】【?扣6011643?】
华纳东方明珠客服电话是多少?(▲18288362750?《?微信STS5099? 】
如何联系华纳东方明珠客服?(▲18288362750?《?微信STS5099? 】
华纳东方明珠官方客服联系方式?(▲18288362750?《?微信STS5099?
华纳东方明珠客服热线?(▲18288362750?《?微信STS5099?
华纳东方明珠24小时客服电话?(▲18288362750?《?微信STS5099? 】
华纳东方明珠官方客服在线咨询?(▲18288362750?《?微信STS5099?
华纳东方明珠客服电话是多少?(▲18288362750?《?微信STS5099? 】【╃q 2704132802╃】
华纳东方明珠开户专线联系方式?(▲18288362750?《?微信STS5099? 】【╃q 2704132802╃】
如何联系华纳东方明珠客服?(▲18288362750?《?微信STS5099? 】【╃q 2704132802╃】
华纳东方明珠官方客服联系方式?(▲18288362750?《?微信STS5099? 】【╃q 2704132802╃】
华纳东方明珠客服热线?(▲18288362750?《?微信STS5099? 】【╃q 2704132802╃】
华纳东方明珠开户客服电话?(▲182(▲18288362750?《?微信STS5099? 】【╃q 2704132802╃】
华纳东方明珠24小时客服电话?(▲18288362750?《?微信STS5099? 】【╃q 2704132802╃】
华纳东方明珠客服邮箱?(▲18288362750?《?微信STS5099? 】【╃q 2704132802╃】
华纳东方明珠官方客服在线咨询?(▲18288362750?《?微信STS5099? 】【╃q 2704132802╃】
华纳东方明珠客服微信?(▲18288362750?《?微信STS5099? 】【╃q 2704132802╃】
华纳公司开户需要哪些材料?(▲18288362750?《?微信STS5099? 】【╃q 2704132802╃】
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099
华纳公司合作开户所需材料?电话号码15587291507 微信STS5099