valores valor una retorno retornan referencia que programacion por parametros lenguaje funciones funcion devolver como c++ gcc vector compiler-optimization compiler-bug

una - Resultado inesperado cuando C++ almacena elemento en std:: vector del valor de retorno de la funciĆ³n



valores de retorno en lenguaje c (2)

Cuando la función implica una reasignación, descubrí que algunos compiladores pueden guardar la dirección antes de la llamada a la función. Lleva el valor de retorno almacenado en la dirección no válida.

Hay un ejemplo para explicar el comportamiento en la descripción anterior.

#include <stdio.h> #include <vector> using namespace std; vector<int> A; int func() { A.push_back(3); A.push_back(4); return 5; } int main() { A.reserve(2); A.push_back(0); A.push_back(1); A[1] = func(); printf("%d/n", A[1]); return 0; }

Hay algunos compiladores comunes de C ++, y el resultado de la prueba es el siguiente.

  • GCC (Colección compilador GNU): Error en tiempo de ejecución o salida 1
  • Clang: salida 5
  • VC ++: salida 5

¿Es un comportamiento indefinido?


El comportamiento no está definido en todas las versiones de C ++ anteriores a C ++ 17. La simple razón es que los dos lados del operador de asignación se pueden evaluar en cualquier orden:

  • Suponiendo que A[1] se evalúa primero, obtiene un int& refiriéndose al segundo elemento de A en ese punto.
  • Luego, se evalúa el func() , que puede reasignar el almacenamiento para el vector, dejando la referencia previamente recuperada int& una referencia colgante.
  • Finalmente, la asignación se realiza, escribiendo en el almacenamiento no asignado. Dado que la memoria caché asignadores estándar, el sistema operativo a menudo no detectará este error.

Solo en C ++ 17, se hizo la regla especial 20 para la asignación:

En cada expresión de asignación simple E1 = E2 y cada expresión de asignación compuesta E1 @ = E2, cada cómputo de valor y efecto secundario de E2 se secuencia antes de cada cálculo de valor y efecto secundario de E1

Con C ++ 17, A[1] debe evaluarse después de la llamada a func() , que luego proporciona un comportamiento definido y confiable.


Si revisa la documentation , en "Invalidación del iterador", verá que push_back() puede invalidar cada iterador si cambia de capacidad, ya que tendría que reasignar la memoria. Recuerde que, para un std::vector , un puntero también es un iterador válido. Debido a que push_back() puede o no reasignar, y usted no tiene forma de saber si lo hará, el comportamiento no está definido.