我们正在玩我们的构建上的铿锵声,我遇到了一些我不完全了解它的行为。我会把代码放在第一位,然后再提出问题。
如果我使用以下代码:
#include <iostream>
using namespace std;
class Param {
public:
Param() {cout << "constructor" << endl;}
~Param() {cout << "destructor" << endl;}
Param(const Param &other) {cout << "copy constructor" << endl;}
Param(Param&& other) {cout << "move constructor" << endl;}
Param& operator=(const Param& other) {cout << "copy assignment" << endl; return *this; }
Param& operator=(Param&& other) {cout << "Param move assignment" << endl; return *this; }
};
class A {
public:
A(const Param& param) : m_param(param){}
Param m_param;
};
int main() {
const Param param;
A a(param);
}
和这个CMake文件:
cmake_minimum_required(VERSION 3.2)
project(clang)
add_executable(clang main.cpp)
set_property(TARGET clang PROPERTY CXX_STANDARD 14)
生成的二进制文件将输出:
constructor
copy constructor
destructor
destructor
如果我然后像这样在CMake文件上启用clang-tidy:
cmake_minimum_required(VERSION 3.2)
project(clang)
add_executable(clang main.cpp)
set_property(TARGET clang PROPERTY CXX_STANDARD 14)
set_property(TARGET clang PROPERTY CXX_CLANG_TIDY "/usr/bin/clang-tidy;-checks=modernize-*;-fix")
编译将打印以下内容:
/.../main.cpp:17:7: warning: pass by value and use std::move [modernize-pass-by-value]
A(const Param& param) : m_param(param){}
^
/.../main.cpp:2:1: note: FIX-IT applied suggested code changes
^
/.../main.cpp:17:7: note: FIX-IT applied suggested code changes
A(const Param& param) : m_param(param){}
^
/.../main.cpp:17:37: note: FIX-IT applied suggested code changes
A(const Param& param) : m_param(param){}
^
/.../main.cpp:17:42: note: FIX-IT applied suggested code changes
A(const Param& param) : m_param(param){}
^
并将代码修改为:
class A {
public:
A(Param param) : m_param(move(param)){}
Param m_param;
};
如果我然后运行我得到的二进制文件:
constructor
copy constructor
move constructor
destructor
destructor
destructor
问题:
1 - 在这两种情况下都需要复制构造函数:
但为什么clang-tidy“认为”额外移动构造函数实际上有帮助?这不仅会增加额外的计算成本吗?
http://clang.llvm.org/extra/clang-tidy/checks/modernize-pass-by-value.html
文档说它假设移动很便宜(这很有意义),但是你不是要把它添加到副本中吗?
编辑:似乎这个问题得到了回答here。我对问题2仍然很好奇。
2 - 假设我误解了某些东西并且铿锵有力是正确的,那么在进行子类化时应该怎么做?两次传递值?
class A {
public:
A(Param param) : m_param(move(param)){}
Param m_param;
};
class B : public A {
public:
B(Param param) : A(move(param)){}
};