关于构造函数初始化列表中使用std::move的clang-tidy建议疑问
关于构造函数初始化列表中使用std::move的clang-tidy建议疑问
嘿,我最近碰到clang-tidy的一个建议有点懵,想跟大伙唠唠这个事儿。clang-tidy给我的提示是:
Clang-tidy: arg is passed by value and only used once; consider moving it.
我的代码大概是这样的:
struct S{ kinda_heavy obj; S(kinda_heavy heavy):obj(heavy){} void do_stuff(); };
我本来是期望调用者会传入一个x值参数的,比如像这样:
S app = S(get_kinda_heavy());
或者调用者也可能用左值来构造,但我一开始觉得临时对象传进来的时候已经是移动构造参数了,直接初始化obj应该没问题啊,为啥clang-tidy要让我用move呢?
其实仔细琢磨一下就明白啦,clang-tidy的建议真的很有道理:
- 当调用者传临时对象(x值)时,参数
heavy确实是通过移动构造来的,但在初始化列表里直接写obj(heavy),会触发拷贝构造把heavy的内容复制给obj——因为heavy在这里是左值,编译器不会自动帮你移动它。 - 如果改成
obj(std::move(heavy)),就能把heavy里的资源直接移动给obj,完全省去了这次不必要的拷贝开销,毕竟heavy在构造函数里只用这一次,用完就销毁了,移动完全安全。
那如果调用者传的是左值呢?比如kinda_heavy h; S s(h);,这时候参数heavy是拷贝构造来的,之后再移动给obj,对比原来的两次拷贝(拷贝参数+拷贝初始化),变成了一次拷贝+一次移动,而移动的开销通常比拷贝小得多,所以不管调用者传左值还是右值,改成move都是更优的选择。
所以听clang-tidy的准没错,把构造函数改成S(kinda_heavy heavy):obj(std::move(heavy)){}就好啦,既能优化右值传入的场景,也能降低左值传入的开销。
内容来源于stack exchange
相关产品推荐
相关产品推荐

