乐趣区

关于程序员:C最佳实践-3-安全性

本系列是开源书 C ++ Best Practises 的中文版,全书从工具、代码格调、安全性、可维护性、可移植性、多线程、性能、正确性等角度全面介绍了古代 C ++ 我的项目的最佳实际。本文是该系列的第三篇。

安全性

尽量应用 const

const 润饰变量或办法,从而通知编译器这些都是不可变的,有助于编译器优化代码,并帮忙开发人员理解函数是否有副作用。此外,应用 const & 能够避免编译器复制不必要的数据。John Carmack 对 const 的评论值得一读。

// Bad Idea
class MyClass
{
public:
  void do_something(int i);
  void do_something(std::string str);
};


// Good Idea
class MyClass
{
public:
  void do_something(const int i);
  void do_something(const std::string &str);
};

认真思考返回类型

  • Getters(成员变量读取 API)

    • 失常状况下,通过返回值读取成员变量时,应用 &const &返回值能够显著进步性能
    • 按值返回更有利于线程平安,如果返回的值就是为了复制应用,就不会有性能损耗
    • 如果 API 返回值应用协变类型 (covariant return types),必须返回&*
  • 长期值和部分值

    • 始终按值返回

参考:\
https://github.com/lefticus/cppbestpractices/issues/21 \
https://twitter.com/lefticus/status/635943577328095232

不要用 const 援用传递和返回简略类型

// Very Bad Idea
class MyClass
{
public:
  explicit MyClass(const int& t_int_value)
    : m_int_value(t_int_value)
  { }

  const int& get_int_value() const
  {return m_int_value;}

private:
  int m_int_value;
}

相同,通过值传递和返回简略类型。如果不打算更改传递的值,请将它们申明为 const,但不要申明为const 援用:

// Good Idea
class MyClass
{
public:
  explicit MyClass(const int t_int_value)
    : m_int_value(t_int_value)
  { }

  int get_int_value() const
  {return m_int_value;}

private:
  int m_int_value;
}

为什么要这样?因为通过援用传递和返回会导致指针操作,而值传递在处理器寄存器中解决,速度更快。

防止拜访裸内存

C++ 中很难在没有内存谬误和透露危险的状况下正确处理裸内存的拜访、调配和回收,C++11 提供了防止这些问题的工具。

// Bad Idea
MyClass *myobj = new MyClass;

// ...
delete myobj;


// Good Idea
auto myobj = std::make_unique<MyClass>(constructor_param1, constructor_param2); // C++14
auto myobj = std::unique_ptr<MyClass>(new MyClass(constructor_param1, constructor_param2)); // C++11
auto mybuffer = std::make_unique<char[]>(length); // C++14
auto mybuffer = std::unique_ptr<char[]>(new char[length]); // C++11

// or for reference counted objects
auto myobj = std::make_shared<MyClass>(); 

// ...
// myobj is automatically freed for you whenever it is no longer used.

std::arraystd::vector代替 C 格调的数组

这两种办法都保障了对象的间断内存布局,并且能够 (而且应该) 齐全取代 C 格调数组,另外这也是不应用裸指针的诸多起因之一。

另外,防止应用 std::shared_ptr 保留数组。

应用异样

返回值(例如boost::optional),能够被疏忽,如果不查看,可能会导致解体或内存谬误,而异样不能被疏忽。另一方面,异样能够被捕捉和解决。可能异样会始终回升到应用程序的最高层级被捕捉、记录到日志中,并触发利用主动重启。

C++ 的设计者之一 Stroustrup 议论过这个话题: Why use exceptions?

用 C ++ 格调的类型转换,而不是 C 格调的类型转换

用 C ++ 格调的强制类型转换 (static_cast<>dynamic_cast<>,…) 代替 C 格调的强制类型转换,C++ 格调的强制转换容许更多的编译器查看,而且相当平安。

// Bad Idea
double x = getX();
int i = (int) x;

// Not a Bad Idea
int i = static_cast<int>(x);

此外,C++ 类型转换格调更为显式,对搜寻更为敌对。

但如果须要将 double 类型转换为 int 类型,请思考重构程序逻辑(例如,对溢出和下溢进行额定查看)。避免出现测量了 3 次,而后切割 0.9999999999981 次这种状况。

不要定义可变参数函数(variadic function)

可变参数函数能够承受数量可变的参数,最驰名的例子可能是printf()。尽管能够定义此类函数,但可能存在平安危险。可变参数函数的应用不是类型平安的,谬误的输出参数可能导致程序以未定义的行为终止。这种未定义的行为可能会导致平安问题。如果应用反对 C ++ 1 的编译器,那么能够应用可变参数模板。

参考: It is technically possible to make typesafe C-style variadic functions with some compilers

额定资源

David Wheeler 的《How to Prevent The Next Heartbleed》一书很好的剖析了代码平安的现状以及如何确保代码平安。

你好,我是俞凡,在 Motorola 做过研发,当初在 Mavenir 做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI 等技术始终保持着浓重的趣味,平时喜爱浏览、思考,置信继续学习、一生成长,欢送一起交流学习。\
微信公众号:DeepNoMind

本文由 mdnice 多平台公布

退出移动版