c++ - Advertencia GCC NRVO/RVO
g++ copy-elision (1)
¿Hay alguna advertencia que nos permita saber si NRVO / RVO se realizó o no, en GCC ?
Encontré que -fno-elide-constructors
desactiva NRVO / RVO , pero NRVO / RVO tiene sus propias condiciones para ocurrir y, a veces, no ocurre. Es necesario saber si NRVO / RVO ocurre para comprender, cuando ocurre una copia-construcción adicional.
Estoy especialmente interesado en las características de tiempo de compilación. Sería bueno si hubiera algún #pragma GCC...
específico (que active el diagnóstico inmediatamente después de sí mismo) o algo que utilice un mecanismo de afirmación estática.
No tengo conocimiento de ningún mensaje de diagnóstico específico de gcc u otro método que pueda resolver su tarea fácilmente. Como ha descubierto, -fno-elide-constructors
desactivará las elecciones de copiar / mover, por lo que sabrá con seguridad que (N) RVO no ocurrirá en ese caso, al menos.
Sin embargo, un vistazo rápido al párrafo 31 en la sección 12.8 de este borrador de trabajo de C ++ 11 establece que:
Cuando se cumplen ciertos criterios, una implementación puede omitir la construcción de copiar / mover de un objeto de clase, incluso si el constructor y / o destructor de copia / movimiento del objeto tiene efectos secundarios. En tales casos, la implementación trata el origen y el destino de la operación de copiar / mover omitida simplemente como dos formas diferentes de referirse al mismo objeto , y la destrucción de ese objeto ocurre en el último momento en que los dos objetos hubieran sido Destruido sin la optimización. Esta elision de operaciones de copia / movimiento, llamada copia de la elision, se permite en las siguientes circunstancias ( que pueden combinarse para eliminar varias copias ):
- en una declaración de retorno en una función con un tipo de retorno de clase, cuando la expresión es el nombre de un objeto automático no volátil (que no sea un parámetro de función o cláusula catch) con el mismo tipo no calificado cv que el tipo de retorno de función, la operación de copiar / mover se puede omitir construyendo el objeto automático directamente en el valor de retorno de la función
...
- cuando un objeto de clase temporal que no se ha vinculado a una referencia (12.2) se copiaría / movería a un objeto de clase con el mismo tipo no cualificado de CV, la operación de copiar / mover se puede omitir construyendo el objeto temporal directamente en el destino de la copia / movimiento omitido
...
Cuando ocurre una copia / movimiento de elision, el objeto automático local es el mismo que el objeto temporal (retorno), que a su vez es el mismo que el objeto "almacenamiento" (donde se almacena el valor de retorno). Por lo tanto, el objeto automático local es el mismo que el objeto de almacenamiento, lo que significa que una comparación de puntero será igual a verdadera. Un ejemplo simple para demostrar esto:
#include <iostream>
#include <vector>
std::vector<int> testNRVO(int value, size_t size, const std::vector<int> **localVec)
{
std::vector<int> vec(size, value);
*localVec = &vec;
/* Do something here.. */
return vec;
}
int main()
{
const std::vector<int> *localVec = nullptr;
std::vector<int> vec = testNRVO(0, 10, &localVec);
if (&vec == localVec)
std::cout << "NRVO was applied" << std::endl;
else
std::cout << "NRVO was not applied" << std::endl;
}
Habilitar / deshabilitar -fno-elide-constructors
cambia el mensaje impreso como se esperaba. Nota: en el sentido más estricto, la comparación del puntero puede depender de un comportamiento indefinido cuando (N) RVO no ocurre, ya que el objeto automático local no existe.
Hacer comparaciones de punteros agregará cruft, pero con la ventaja de ser independiente del compilador.