2010-01-08 14 views
8

Desde el siguiente código, RVO Si ha sucedido, espero ver las 2 direcciones que apuntan en la misma ubicación, sin embargo, este no es el caso (mi compilador es VC9.0 MS)¿Cuándo debería iniciarse RVO?

#include <iostream> 
#include <string> 

std::string foo(std::string& s) 
{ 
    std::cout << "address: " << (unsigned int)(&s) << std::endl; 
    return s; 
} 

int main() 
{ 
    std::string base = "abc"; 
    const std::string& s = foo(base); 
    std::cout << "address: " << (unsigned int)(&s) << std::endl; 
    std::cout << s << std::endl; 
    return 0; 
} 

¿En qué condiciones debería estar sucediendo RVO?

por cierto, me estoy basando mi pregunta en el siguiente análisis: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

+0

I la pregunta de OP, él está obteniendo una referencia de lo que se devuelve de la función.Normalmente, todos deberían decir "¡horror, se va a romper!" pero en este caso el hecho de que él lo declaró const extiende la vida de lo temporal al final del alcance, salvándole la caída esperada. Pero en cualquier caso, él no está usando ningún valor de retorno de todos modos debido a esa referencia. – Lightness1024

Respuesta

1

Usted parece no entender RVO, probar este ejemplo (en realidad NRVO):

std::string foo(const char* const s) 
{ 
    std::string out(s); 
    std::cout << "address: " << (void*)(&out) << std::endl; 
    return out; 
} 

int main() 
{ 
    std::string s = foo("abc"); 
    std::cout << "address: " << (void*)(&s) << std::endl; 
} 
+1

Creo que está equivocado: http://codepad.org/BuTRF0Ra –

+1

¿Ha activado las optimizaciones, etc. (* Propiedades del proyecto - C++ - Optimización - O2 o superior *)? Por cierto, RVO no es vinculante para el compilador. –

+2

aaah Veo, técnicamente, algo así como en línea donde el compilador puede decidir cuándo y dónde quiere optimizar. –

2

no sé las condiciones completas, pero creo que el hecho de que está devolviendo un parámetro y no una instancia creada en la función está causando el problema en su ejemplo.

Para mí, la siguiente mostraron la misma dirección para ambos:

#include <iostream> 
#include <string> 

std::string foo() 
{ 
    std::string s("rvo!"); 
    std::cout << "address: " << (void *)(&s) << std::endl; 
    return s; 
} 

int main() 
{ 
    const std::string s = foo(); 
    std::cout << "address: " << (void *)(&s) << std::endl; 
    std::cout << s << std::endl; 
    return 0; 
} 

seguimiento para darid de comentar

Los codepad about page documentos que para ello el uso del -fno-Elide-constructores para C++ . La documentación para esta opción de formar g ++ estado página del manual:

estándar del C++ permite una implementación de omitir la creación de un temporal que sólo se utiliza para inicializar otro objeto de la mismo tipo. Al especificar esta opción, se desactiva esa optimización, y obliga a G ++ a llamar al constructor de copia en todos los casos.

En mi máquina, compilar con -fno-elide-constructors previene RVO, pero compilar sin permite.

+2

Creo que estás equivocado: http://codepad.org/j9G52Abp –

+1

@darid - He agregado mi respuesta para refutar el hecho de que el teclado no exhibe RVO. –

4

La respuesta correcta es "siempre que el compilador lo desee". Tal comportamiento no es obligatorio (pero está permitido) por el estándar, y las condiciones exactas en las que se inicia varían de compilador a compilador y de versión a versión.

Como regla general, el compilador es más inteligente que usted y trabaja en su mejor interés. No lo cuestiones

Las referencias rvalue en C++ 0x son una especie de versión manual de RVO.

Edit: Mirando más de cerca su código, definitivamente está malentendiendo RVO. Debido a que su parámetro es una referencia, no hay forma de que el valor de retorno de la función tenga la misma dirección.

8

RVO generalmente se aplica cuando devuelve un nombre temporal sin nombre, pero no si devuelve un objeto creado anteriormente.

std::string foo() { 
    return std::string("hello world"); // RVO 
} 

std::string foo() { 
    std::string str("hello world"); 
    bar(); 
    return str; // Not RVO 
} 

std::string foo(std::string str) { 
    return str; // Not RVO 
} 

Una versión más general es NRVO (Named optimización valor de retorno), que también trabaja en las variables con nombre.

std::string foo() { 
    std::string str("hello world"); 
    bar(); 
    return str; // NRVO 
} 

std::string foo(std::string str) { 
    return str; // Not NRVO, as far as I know. The string is constructed outside the function itself, and that construction may be elided by the compiler for other reasons. 
} 

std::string foo(std::string str) { 
    std::string ret; 
    swap(ret, str); 
    return ret; // NRVO. We're returning the named variable created in the function 
} 
+1

¿Quiso decir 'return ret', en la versión con intercambio, por supuesto? – Tony

Cuestiones relacionadas