计算机 · 2021年7月2日 0

C++踩坑笔记

  1. ostringstream的引用作为函数参数的坑
    想着用ostringstream的引用来搞几个json的工具函数,就像下面这样
    template <class T>
    void json_start(std::ostringstream &oss, const char *key, T val) {
        oss << "{" << key << val;
    }

会报错:

error: no match for ‘operator<<’ in ‘oss << “{“’

  1. put_time函数
  2. non-const references to rvalues的含义
    为了防止你写一个函数参数为引用的函数,然后不小心传了一个兼容的类型进去,这个类型自动转为了函数参数的类型,但是转换了之后却变成了一个右值,你并没有达到想要的通过这个函数去改变这个传入的函数参数的目的。

可变参数模板

几篇不错的链接:

  • https://arne-mertz.de/2016/11/more-variadic-templates/
  • https://raymii.org/s/snippets/Cpp_variadic_template_recursive_example.html
  • https://kubasejdak.com/techniques-of-variadic-templates
  • https://gist.github.com/daniel-j-h/c4a7788fd560e94db9f7
  • https://www.experts-exchange.com/articles/32502/None-recursive-variadic-templates-with-std-initializer-list.html
  • https://en.cppreference.com/w/cpp/language/parameter_pack

IDE

netbeans解析c++11代码时总是提醒错误

  1. 在属性=>代码帮助=>c++编译器=>c++标准选c++11;
  2. 在属性=>代码帮助=>c++编译器=>预处理程序定义里加一个__cplusplus=201103L的宏定义,可能是上面的c++11标准设置有bug,经常会不生效,才导致需要再加一个宏定义来提醒IDE使用c++11标准来解析。
    参考:https://bz.apache.org/netbeans/show_bug.cgi?id=242729

address sanitizer

clang文档
gcc文档
关于so库和可执行文件都使用address sanitizer时的编译问题
使用so库时可能遇到的bug:

  • https://reviews.llvm.org/D33784
  • https://www.mail-archive.com/llvm-bugs@lists.llvm.org/msg14550.html
    解决方法是用LD_PRELOAD先加载asan库,再加载应用程序所需的so库:https://blog.csdn.net/zqh1630/article/details/103990483
    sanitizer和cuda搅在一起,可能还有bug:
  • https://forums.developer.nvidia.com/t/cuda-runtime-library-and-addresssanitizer-incompatibilty/63145
  • https://github.com/google/sanitizers/issues/629
    解决方法就是运行的时候设置下asan的参数:ASAN_OPTIONS=protect_shadow_gap=0,然而对我的合流进程并没有效果。。。cuda依然初始化出错。
    由于这些坑爹的问题,最后还是靠valgrind解决了问题,而valgrind使用过程中也出现了setrlimit的报错,解决办法就是注释掉setrlimit相关的代码。

编译时期的反射

想要枚举类里的每一个成员变量,只能使用支持了反射的c++17或者boost里的fusion(自己实现也行),而且还得写一句代码来注册这些成员变量。

  • https://github.com/qicosmos/iguana

指向成员变量的指针

https://en.cppreference.com/w/cpp/language/pointer指向成员变量的指针并不是一个指向某个内存地址的指针,而是记录的类成员的偏移量;

后置返回类型(trailing return types)

https://community.ibm.com/community/user/ibmz-and-linuxone/blogs/fang-lu2/2020/03/24/introduction-to-the-c11-feature-trailing-return-types?lang=en为了让函数的返回类型的写法可以更generalized,于是c++11支持了返回类型后置的写法。这样可以用参数列表里的变量结合decltype,来声明不用返回类型后置就无法表示的返回类型。

initializer_list不能被复制

一些有助于发现代码异常的编译选项

https://clang.llvm.org/docs/DiagnosticsReference.html#woverloaded-virtual

抑制编译warning的几种方式

https://nelkinda.com/blog/suppress-warnings-in-gcc-and-clang/

clang找不到头文件

https://www.berezovskyi.me/2015/02/clang-fatal-error-headers-not-found/

NULL与nullptr的区别

https://www.quora.com/Whats-the-difference-between-NULL-and-nullptr-in-C++#:~:text=nullptr%20is%20a%20keyword%20that,zero%2C%20you%20should%20use%20nullptr%20.

placement new

https://www.geeksforgeeks.org/placement-new-operator-cpp/

Cannot bind packed field

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36566
其实可以看这个stackoverflow上的问题:
https://stackoverflow.com/questions/27491432/why-cant-i-return-a-reference-to-a-packed-field
简单说就是为什么不能对于使用了packed标记的class/struct,不能创建对该类中成员的引用?
原因在该问题下面的一个回答里:

On architectures that aren’t byte addressable,the compiler still lets you access non-aligned fields by doing memory transforms behind the scenes (e.g. masking and shifting) to get your desired value. It only knows to do this because the struct is packed at compile time. If the compiler loses that packed information, then it may try to directly access a memory location that’s not supported and will hard fault. Even though in the OPs question it would make no difference, GCC plays it safe and disallows the operation.

就是说packed的class/struct里面的成员的地址可能违反了该成员类型的对齐要求,当我们直接使用a.s这种方式来读写类中的成员时,编译器仍然知道这是packed类里面的成员,会多生成一些代码处理成员地址没有对齐的问题。但是当我们把成员地址赋给另外的指针或者引用时,这个地址是packed类里的成员地址的信息就被丢掉了,编译器在使用这个指针或者引用时就不会添加地址不对齐的代码,程序就可能出错。

静态代码检查工具

scan-build

CodeChecker

snap install --classic codechecker 

codechecker会自动检测clang命令的存在,为了使用clang-10的Cross Unit Translation特性,把默认的clang给卸载掉,安装clang-10,然后把clang-10设置为默认的clang

sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-10 100
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-10 100

codechecker使用:

codechecker check -b "cd ~/your-project && make clean && make" -o ./results 

将结果转换成为html文件:

codechecker parse -e html ./results -o ./reports_html

使用clang10的ctu特性进行分析

codechecker analyze --ctu compile_commands.json -o reports

这个compile_commands.json可用使用上一个check命令生成的reports里生成的json文件。analyze的结果也可以按照和check一样的方式转换为html文件进行查看。

编译参数

-shared隐式包含了-fPIC,但是不是所有的系统都支持-shared选项,因此很多时候还是会见到这两个参数一起用.