title abseil C++ Tips
date: 2022-10-28 00:00
url: abseil_cpp_tips
学习abseil C++ Tips

Tip of the Week #1: string_view

当函数参数为(const) string时,常见的一般有3种方法,第三种方法可能不太常见。

// C Convention
void TakesCharStar(const char* s);

// Old Standard C++ convention
void TakesString(const std::string& s);

// string_view C++ conventions
void TakesStringView(absl::string_view s);    // Abseil
void TakesStringView(std::string_view s);     // C++17

前面两种方法只有当参数类型匹配时才比较方便,如果对void TakesCharStar(const char* s);函数传入std::string,需要调用c_str()函数。

void AlreadyHasString(const std::string& s) {
  TakesCharStar(s.c_str());               // explicit conversion
}

如果是对函数void TakesString(const std::string& s);传入const char*,可以直接调用,但是实际上会触发std::string的拷贝构造函数,程序效率存在问题。

void AlreadyHasCharStar(const char* s) {
  TakesString(s); // compiler will make a copy
}

What to Do ?
可以使用c++17中的sting_view或absl::string_view,string_view可以支持两种类型直接调用,虽然存在隐士类型转换,但不会拷贝整个数据,所以不存在O(n)的内存消耗。string_view只是记录了自身对应字符串的地址信息。当const char*作为参数时,隐含传入了strlen()作为string_view的构造参数。

void AlreadyHasString(const std::string& s) {
  TakesStringView(s); // no explicit conversion; convenient!
}

void AlreadyHasCharStar(const char* s) {
  TakesStringView(s); // no copy; efficient!
}

string_view详细教程参考:learn c++ string_view

尽量以const,enum,inline替换#define

宁可以编译器替换预处理器。
例如#define ASPECT_RATIO 1.653
符号ASPECT_RATIO从未被编译器看见,在预处理阶段已经完成替换,运行时错误时如果在代码中存在多个1.653将存在困惑。

解决办法是使用const double AspectRatio = 1.653,编译后进入符号表。
为了将常量的作用域限制于class内,你必须让它成为class的一个成员,为了确保此常量至多只有一份实例,你必须使用static.

#include <iostream>
using namespace std;

class GamePlayer {
private:
    static const int NumTurns = 5;//常量声明式
    int score[NumTurns];
};

int main(){
    return 0;
}

如果需要取某个class专属常量的地址,必须使用如下方式:

#include <iostream>
using namespace std;

class GamePlayer {
public:
    static const int NumTurns = 5;
    int score[NumTurns];
};

const int GamePlayer::NumTurns;
int main(){
    cout << GamePlayer::NumTurns << ",address NumTurns:"<<&GamePlayer::NumTurns;
    return 0;
}