2012-04-24 12 views
8

Supongamos que tengo una clase donde el constructor de copia es privada y no implementado (para que el objeto no copiable)¿Se permite RVO cuando un constructor de copia es privado y no está implementado?

class NonCopyable { 
// whatever 
private: 
    NonCopyable(const NonCopyable&); 
    void operator=(const NonCopyable&); 
}; 

Ahora en alguna función miembro de la misma clase que escribir código que devuelve un objeto de esa clase:.

NonCopyable NonCopyable::Something() 
{ 
    return NonCopyable(); 
} 

que es un caso cuando RVO podría poner en

RVO todavía requiere que un constructor de copia es accesible. Dado que la posible llamada al constructor de copia se realiza desde la misma función de miembro de clase, se puede acceder al constructor de copia . Entonces técnicamente RVO es posible a pesar del hecho de que la intención era prohibir el uso del constructor de copia.

¿Se permite RVO en tales casos?

Respuesta

3

Su ejemplo es bastante interesante.

Esta es la declaración típica de C++ 03.

class NC { 
public: 
    NC NC::Something() { 
     return NC(); 
    } 

private: 
    NC(NC const&); 
    NC& operator=(NC const&); 
}; 

Aquí, como se ha señalado, RVO puede patear a pesar de que semánticamente queríamos evitar la copia.

En C++ 03, la solución es delegar:

class NC: boost::noncopyable { 
public: 
    NC NC::Something() { // Error: no copy constructor 
     return NC(); 
    } 
}; 

En C++ 11, tenemos la alternativa de utilizar la palabra clave delete:

class NC { 
public: 
    NC NC::Something() { // Error: deleted copy constructor 
     return NC(); 
    } 

private: 
    NC(NC const&) = delete; 
    NC& operator=(NC const&) = delete; 
}; 

Pero a veces, nos desea evitar la copia, pero desea permitir el Builder (como en el Patrón).

En este caso, su ejemplo funciona , siempre que RVO emita, lo cual es un poco molesto ya que, en esencia, no es estándar. Se debe proporcionar una definición del constructor de copias pero no desea que se use.

En C++ 11, este uso se admite mediante la eliminación de operaciones de copia y la definición de operaciones de movimiento (incluso en privado).

6

Sí, RVO estaría permitido en este caso, al menos si la persona que llama de Something() era un miembro de la clase o un amigo.

Creo que esta es una de las razones por las que la herencia privada de una clase que no se puede copiar es mejor que hacerlo manualmente en cada clase en la que se desea evitar la copia. En ese caso, no hay laguna accidental.

Por ejemplo, el uso de boost::noncopyable:

class NonCopyable : private boost::noncopyable { 
public: 
    NonCopyable() {}; 
    NonCopyable Something(); 
}; 

NonCopyable NonCopyable::Something() 
{ 
    return NonCopyable(); // causes compile time error, not link time error 
} 
+3

O simplemente usando las funciones C++ 11 'delete' para eliminar claramente la ambigüedad en la etapa de compilación (en lugar de la etapa de enlace) de que la clase no se copiará. –

+0

@ Matthieu: sí, es un mecanismo mejor si no tienes que preocuparte por los compiladores heredados (supongo que ya podemos llamarlos legacy, incluso si estoy seguro de que todavía tienen un gran dominio en el uso). –

0

Está permitido, pero es posible obtener un error de enlace debido a que el constructor de copia no está implementado. Si proporciona un cuerpo para NonCopyable(const NonCopyable&), funcionaría.

+1

No habría error de enlace porque con RVO no hay una llamada real al copiador. –

+0

Puede haber_ un error de enlace :) P. ej. si las optimizaciones están desactivadas Tengo el error en MSVC incluso con optimizaciones activadas. – Andrey

+0

Michael sigue estando en lo cierto: no hay ningún error de enlace _si_ se ha realizado la Optimización del valor devuelto (que fue el escenario discutido). Eso obviamente implica que esa optimización particular no está desactivada. – MSalters

0

Un punto importante puede eclipsar la pregunta real.

What is the use case of such function if RVO is allowed ?

Esta función puede ser llamada de 3 maneras y 2 de ellos será un error del compilador:

NonCopyable obj; 
NonCopyable obj2 = obj; // 1 --> error 
NonCopyable &r = obj; // 2 --> error 
const NonCopyable &rc = obj; // 3 --> ok, but dangerous (may lead to UB) 

uno no puede usar el objeto devuelto de manera efectiva, por lo que realmente no importa si el RVO está permitido o no.

Cuestiones relacionadas