C++ 最佳实践 | 3. 安全性

简介: C++ 最佳实践 | 3. 安全性

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


C++最佳实践:

  1. 工具
  2. 代码风格
  3. 安全性(本文)
  4. 可维护性
  5. 可移植性及多线程
  6. 性能
  7. 正确性和脚本


安全性


尽量使用 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),必须返回&*
  • 临时值和局部值
  • 始终按值返回


不要用 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》一书很好的分析了代码安全的现状以及如何确保代码安全。

目录
相关文章
|
1月前
|
存储 安全 算法
【C++智能指针 相关应用】深入探索C++智能指针:跨进程、动态库与最佳实践
【C++智能指针 相关应用】深入探索C++智能指针:跨进程、动态库与最佳实践
86 5
|
1月前
|
Rust 安全 程序员
Rust与C++:内存管理与安全性的比较
本文将对Rust和C++两种编程语言在内存管理和安全性方面进行深入比较。我们将探讨Rust如何通过其独特的所有权系统和生命周期管理来消除内存泄漏和悬挂指针等常见问题,并对比C++在这方面的挑战。此外,我们还将讨论Rust的类型系统和编译器如何在编译时捕获许多常见的运行时错误,从而提高代码的安全性。
|
1月前
|
C++
C++ 编程必备:对象生命周期管理的最佳实践
在C++中,对象的生命周期是指对象存在的时间段,从对象创建到对象销毁的整个过程。正确地管理对象的生命周期是编写高效、可靠C++代码的关键之一
72 1
|
1月前
|
消息中间件 负载均衡 监控
【ZMQ PUB模式指南】深入探究ZeroMQ的PUB-SUB模式:C++编程实践、底层原理与最佳实践
【ZMQ PUB模式指南】深入探究ZeroMQ的PUB-SUB模式:C++编程实践、底层原理与最佳实践
562 1
|
1月前
|
NoSQL API Redis
最佳实践|如何使用c++开发redis module
本文将试着总结Tair用c++开发redis module中遇到的一些问题并沉淀为最佳实践,希望对redis module的使用者和开发者带来一些帮助(部分最佳实践也适用于c和其他语言)。
76395 0
|
1月前
|
安全 vr&ar C++
C++:编程语言的演变、应用与最佳实践
C++:编程语言的演变、应用与最佳实践
|
1月前
|
C++
C++ 访问说明符详解:封装数据,控制访问,提升安全性
C++ 中的访问说明符(public, private, protected)用于控制类成员的可访问性,实现封装,增强数据安全性。public 成员在任何地方都可访问,private 只能在类内部访问,protected 则允许在类及其派生类中访问。封装提供数据安全性、代码维护性和可重用性,通过 setter/getter 方法控制对私有数据的访问。关注公众号 `Let us Coding` 获取更多内容。
36 1
|
1月前
|
安全 算法 编译器
【C++ 泛型编程 进阶篇】深入探索 C++ STL 容器的嵌套类型:识别、运用与最佳实践
【C++ 泛型编程 进阶篇】深入探索 C++ STL 容器的嵌套类型:识别、运用与最佳实践
108 7
|
1月前
|
设计模式 安全 C++
【C++ const 函数 的使用】C++ 中 const 成员函数与线程安全性:原理、案例与最佳实践
【C++ const 函数 的使用】C++ 中 const 成员函数与线程安全性:原理、案例与最佳实践
249 2
|
1月前
|
程序员 开发工具 git
【程序员英语 代码提交】C++工程师的代码提交艺术:git commit 时 精确表达与最佳实践
【程序员英语 代码提交】C++工程师的代码提交艺术:git commit 时 精确表达与最佳实践
128 1