1. 拷贝和移动
左值赋值类操作采用拷贝构造函数, 一般赋值都是拷贝构造函数, 初始化尽量使用 新式的{}初始化方式
右值赋值类操作采用移动构造函数,函数返回采用的是移动构造函数, 函数返回会使用移动构造函数产生一个临时变量,临时变量再赋值给 变量,若无移动构造函数,两次赋值均使用拷贝构造函数(均为采用右值赋值)。stb::move()可以取一个左值的右值
关于各种默认的构造函数:
https://docs.microsoft.com/en-us/cpp/cpp/constructors-cpp?redirectedfrom=MSDN&view=msvc-160
2.左值右值场景总结
&a 为右值,其中&取址符只能用于左值之前
同理 *a 为右值, *只能用于左值前面
本质上来说,右值指的是临时变量
T a = 默认是传值,即值拷贝
T& a = lvalue 其中a为左值引用
T&& a = rvalue 其中a为右值的引用
3.关于函数式编程中几个例子
// 使用模板的方式
template <typename F>
double f(const vector<double>& origV, F subF ) {
double max = *origV.begin();
for (double i : origV ) {
if (subF(i, max)) {
max = i;
}
}
return max;
}
// 使用using函数式声明方式
using FF = bool (*)(double x, double y);
using FFF = function<bool(double, double)>;
double ff(const vector<double>& origV, FF subF) {
double max = *origV.begin();
for (double i : origV ) {
if (subF(i, max)) {
max = i;
}
}
return max;
}
void showvec(const std::vector<double>& line) {
cout << ff(line, [](double x, double y){ return x > y;}) << endl; // lambda 函数
// for (auto iter = line.cbegin(); iter != line.cend(); iter++) {
// cout << (*iter) << endl;
// }
}
3.关于const 函数
如果采用"按址传递方式"的函数返回值加const 修饰,那么函数返回值(即地址)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。
如果采用"按值传递方式"的函数返回值加const 修饰,由于函数会把返回值复制到外部临时的存储单元中,加const 修饰没有任何价值。
类的成员函数后面加 const,表明这个函数不可以对这个类对象的数据成员(准确地说是非static数据成员)作任何改变。 (const 对象只能调用const成员函数)
4. 关于内部链接 和 外部链接
符号可以在声明多次,但只能被定义一次
-
外部链接:默认为外部链接
-
内部链接:
函数:static、inline
变量:const、constexpr、static -
inline (constexpr 修饰的函数默认是内联的)的内部性体现在 申明和定义必须在同一编译单元内存在,不会从外部去查找,但其编译链接存在一定的特殊性。这里具体选择哪一个编译单元的的版本,存在一定随机性,如果内联成功,则是各编译单元的版本,如果内联失败,则是随机选择一个版本,所以不同编译单元若定义不一致则其实际表现是未定义的,不通的编译配置下会选择不同的版本;实际inline成功的函数不能获取函数指针。
最佳实践:
参考:https://www.zhihu.com/question/458849130;https://zhuanlan.zhihu.com/p/380389282,结论如下:
https://zh-blog.logan.tw/2020/03/22/cxx-17-inline-variable/
https://en.cppreference.com/w/cpp/language/inline
- static的内部性也必须是同一编译单元存在,不会从外部查找,但基本质是每个编译单元都会重新编译一个自己版本的函数
- extern const定义变量 可以将const变量的从内部链接 提升为 外部链接
- extern static 无效,仍是内部性
- extern inline 用法比较奇怪, 建议少使用,可以参考:
对于非成员函数和变量,最佳实践是在头文件 中申明(变量采用extern),在源文件中定义;
凡属于在头文件中定义的变量函数,均需要考虑在多个源文件中引用的重定义问题;
函数采用 static inline可以变为内部性; 变量采用static const 变为内部性
5 修饰符
- inline函数修饰可以只在申明和定义的移除出现, 由于内联优化, 需要保证 inline声明和定义在同一编译单元出现。比如对于类成员函数,inline申明的成员函数, 必须和类申明在同编译单元出现。
// comm.h
int Sum();
inline int Sum() {
return 6;
}
// comm1.h
inline int Sum();
int Sum(){
retrun 6};
- static成员函数修饰必须只在类声明中出现; static普通函数则需要申明和定义均有static修饰,由于 内部链接性,需要保证申明必须在同一编译单元
- 函数的默认值只能在声明或定义中一处出现