[Notas de aprendizaje del lenguaje C]: Seguridad

Modificar constvariables o métodos para decirle al compilador que son inmutables ayuda al compilador a optimizar el código y ayuda a los desarrolladores a comprender si la función tiene efectos secundarios. Además, el uso const &evita que el compilador copie datos innecesarios. Vale la pena leer el comentario de John Carmack sobre ```const```[2].

// 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);
};

Piense detenidamente en los tipos de devolución

  • Getters (API de lectura de variables miembro)

    • En circunstancias normales, al leer variables miembro a través de valores de retorno, el uso &de const &valores de retorno puede mejorar significativamente el rendimiento.

    • Devolver por valor es más propicio para la seguridad de los subprocesos. Si el valor devuelto es para copiar y usar, no habrá pérdida de rendimiento.

    • Si el valor de retorno de la API utiliza tipos de retorno covariantes, debe devolver &o*

  • Valores temporales y locales.

    • Siempre devuelto por valor

No utilice referencias constantes para pasar y devolver tipos simples

// 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;
}

En cambio, los tipos simples se pasan y devuelven por valor. Si no planeas cambiar los valores pasados, declaralos como const, pero no como constreferencias:

// 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;
}

¿Por qué esto es tan? Debido a que pasar y regresar por referencia da como resultado operaciones de puntero, el paso por valor se maneja en los registros del procesador y es más rápido.

Evite acceder a la memoria sin procesar

Es difícil en C++ manejar correctamente el acceso, la asignación y la desasignación de la memoria sin procesar sin el riesgo de errores y fugas de memoria [3], y C++ 11 proporciona herramientas para evitar estos problemas.

// 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.

Utilice std::arrayo std::vectoren lugar de matrices estilo C

Ambos métodos garantizan un diseño de memoria contigua de los objetos y pueden (y deben) reemplazar completamente las matrices de estilo C, y son una de las muchas razones para no utilizar punteros sin formato.

Además, evite usar ```std::shared_ptr``` para guardar matrices[4].

Usar excepción

Los valores de retorno (por ejemplo boost::optional) se pueden ignorar y pueden causar fallas o errores de memoria si no se verifican, mientras que las excepciones no se pueden ignorar. Las excepciones, por otro lado, pueden detectarse y gestionarse. Es posible que la excepción aumente al nivel más alto de la aplicación, donde será detectada, registrada en el registro y desencadenará un reinicio automático de la aplicación.

Stroustrup, uno de los diseñadores de C++, habló sobre este tema: ¿Por qué utilizar excepciones?[5]

Utilice conversiones de estilo C++ en lugar de conversiones de estilo C

Reemplace las conversiones de estilo C con conversiones de estilo C++ ( static_cast<>,, dynamic_cast<>...), que permiten más comprobaciones del compilador y son bastante seguras.

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

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

Además, el estilo de conversión de tipos de C++ es más explícito y más fácil de buscar.

Pero si necesita doubleconvertir tipos en inttipos, considere refactorizar la lógica de su programa (por ejemplo, comprobaciones adicionales de desbordamiento y subdesbordamiento). Evite la situación de medir 3 veces y luego cortar 0,9999999999981 veces.

No definir funciones variadas

Una función variada puede aceptar un número variable de argumentos, quizás el ejemplo más famoso sea printf(). Aunque es posible definir dichas funciones, puede haber riesgos de seguridad. El uso de funciones variadas no es seguro para los tipos y los parámetros de entrada incorrectos pueden hacer que el programa finalice con un comportamiento indefinido. Este comportamiento indefinido puede causar problemas de seguridad. Si usa un compilador que admita C++1, puede usar plantillas variadas.

Supongo que te gusta

Origin blog.csdn.net/Jiangziyadizi/article/details/129372662
Recomendado
Clasificación