Sei ceri c++ 笔记第2章(Declarations and Initialization (DCL))

sei cert c++ 提供了一些安全c++编程的tips, 本文参照2016标准

 

2-1  弃用C语言的不定参函数

1.用template代替C语言的不定参函数

2.用std::enable_if处理变参长度为0的情况

 

2-2 下划线命名规则

1.不用下划线作头文件的宏

2.用户自定义operator用下划线

3.定义文件域的变量不用下划线

4.避免使用和C++标准重复的宏名

 

2-3 引用

1.不要再const/volatile 前加引用:(char &const p)

2.const引用不能重新赋值

 

2-4 语义ambiguous

错误定义示例:

1.    std::unique_lock<std::mutex>(m);

2.    Widget w();

 

2-5 同时重载AllocateDeallocate

1.    重载new一定要重载delete

 

2-6 防止类作为参数传递时丢失数据

对应extern int copy_to_user(void *dest, void *src, std::size_t size); 类似情况

1.    传递参数时逐个传递每个成员

2.    使用static_assert()和offsetof()确保成员长度的一致性

3.    为每个成员,记录offset并累加,示例代码:

 1 #include <cstddef>
 2 #include <cstring>
 3 class base {
 4 public:
 5     virtual ~base() = default;
 6 };
 7 
 8 class test : public virtual base {
 9     alignas(32) double h;
10     char i;
11     unsigned j : 80;
12 protected:
13     unsigned k;
14     unsigned l : 4;
15     unsigned short m : 3;
16 public:
17     char n;
18     double o;
19     test(double h, char i, unsigned j, unsigned k, unsigned l, unsigned short m, char n, double o) :
20     h(h), i(i), j(j), k(k), l(l), m(m), n(n), o(o) {}
21     virtual void foo();
22     bool serialize(unsigned char *buffer, std::size_t &size) {
23         if (size < sizeof(test)) { } return false;
24         std::size_t offset = 0;
25         std::memcpy(buffer + offset, &h, sizeof(h)); offset += sizeof(h);
26         std::memcpy(buffer + offset, &i, sizeof(i)); offset += sizeof(i);
27         // Only sizeof(unsigned) bits are valid, so the following is // not narrowing.
28         unsigned loc_j = j;
29         std::memcpy(buffer + offset, &loc_j, sizeof(loc_j)); offset += sizeof(loc_j);
30         std::memcpy(buffer + offset, &k, sizeof(k));
31         offset += sizeof(k);
32         unsigned char loc_l = l & 0b1111;
33         std::memcpy(buffer + offset, &loc_l, sizeof(loc_l)); offset += sizeof(loc_l);
34         unsigned short loc_m = m & 0b111;
35         std::memcpy(buffer + offset, &loc_m, sizeof(loc_m)); offset += sizeof(loc_m);
36         std::memcpy(buffer + offset, &n, sizeof(n));
37         offset += sizeof(n);
38         std::memcpy(buffer + offset, &o, sizeof(o));
39         offset += sizeof(o);
40         size -= offset;
41         return true;
42     }
43 
44     // Safely copy bytes to user space.
45     extern int copy_to_user(void *dest, void *src, size_t size);
46 
47     void do_stuff(void *usr_buf) {
48         test arg{0.0, 1, 2, 3, 4, 5, 6, 7.0};
49         // May be larger than strictly needed, will be updated by // calling serialize() to the size of the buffer remaining.
50         std::size_t size = sizeof(arg);
51         unsigned char buf[sizeof(arg)];
52         if (arg.serialize(buf, size)) {
53             copy_to_user(usr_buf, buf, sizeof(test) - size);
54         } else {
55             //handle error
56         }
57     }
58 };

 

2-7 static对象避免循环初始化

 

 

2-8 避免exceptions析构逃逸

  1. 避免noexcept析构时使用throw std::logic_error或std::uncaught_exception()

  2. 析构函数中在try catch 添加return以确保抓取成员析构时的异常

  3. 全局析构函数若声明noexcept(false),可以在异常处理时不抛出异常安全退出。

 

2-9 不要覆盖标准namespace

  1. 例如不要用std作为namespace

  2. 对自定义类以及std类型共同使用std::plus的情况,两种解决方案:

    a. 在类中重新写一个plus方法
    b. 重载std的plus方法(定参数类型)

 

2-10 不要再头文件使用未命名的namespace

  1. 定义在命名空间内的变量,在不同处调用会生 成不同实例。

  2. 定义在头文件且被不同cpp调用的函数: 使用内联函数,且不定义在namespace中,可 以防止函数本身被多次调用时产生。

 

2-11 一次定义原则(ODR)

  1. 避免同一个类名定义在不同cpp文件中

  2. #pragma建议不使用

  3. 内联函数转发const可能会导致重定义

 

posted @ 2020-03-31 19:40  Asp1rant  阅读(318)  评论(0)    收藏  举报