El siguiente programa corto
#include <vector>
#include <iostream>
std::vector<int> someNums()
{
return {3, 5, 7, 11};
}
class Woop
{
public:
Woop(const std::vector<int>& nums) : numbers(nums) {}
void report()
{
for (int i : numbers)
std::cout << i << ' ';
std::cout << '\n';
}
private:
const std::vector<int>& numbers;
};
int main()
{
Woop woop(someNums());
woop.report();
}
tiene un problema de referencia pendiente, que ningún compilador parece advertir. El problema es que los temporales pueden estar vinculados a const-refs, que luego puede mantener. La pregunta entonces es; ¿Hay algún método para evitar entrar en este problema? Preferiblemente uno que no implique sacrificar la corrección constante, o siempre hacer copias de objetos grandes.
std::unique_ptr
para propiedad exclusivastd::shared_ptr
o propiedad compartida ostd::weak_ptr
, al menos, para reconocer datos perdidos).-fsanitize=address
. No creo que haya una mejor práctica para evitarlo sin sacrificar el rendimiento.Respuestas:
En una situación en la que algún método mantiene una referencia después de devolverla, es una buena idea utilizarla en
std::reference_wrapper
lugar de la referencia normal:Woop (std::vector<int> const &&) = delete;
para su método:fuente
Una forma de hacer que su clase sea menos vulnerable podría ser agregar un constructor eliminado que tome una referencia correcta. Esto evitaría que su instancia de clase haga enlaces a temporales.
Este constructor eliminado en realidad haría que el código O / P no se compilara, ¿cuál puede ser el comportamiento que está buscando?
fuente
Estoy de acuerdo con las otras respuestas y comentarios en que debe pensar detenidamente si realmente necesita almacenar una referencia dentro de la clase. Y si lo hace, probablemente querrá un puntero no constante a un vector constante en su lugar (es decir
std::vector<int> const * numbers_
).Sin embargo, si ese es el caso, encuentro que las otras respuestas publicadas actualmente están fuera del punto. Todos te muestran cómo hacer
Woop
propios esos valores.Si puede asegurarse de que el vector que pasa sobrevivirá a su
Woop
instancia, entonces puede deshabilitar explícitamente la construcciónWoop
de un valor r. Eso es posible usando esta sintaxis de C ++ 11:Ahora su código de ejemplo ya no se compilará. El compilador da un error similar a:
PD: Probablemente desee un constructor explícito, consulte, por ejemplo, ¿qué significa la palabra clave explícita? .
fuente
Para evitar ese caso en particular, puede optar por tomar un puntero (ya
Weep(&std::vector<int>{1,2,3})
que no está permitido) o puede tomar una referencia no constante que también generará un error temporal.Estos todavía no garantizan que el valor siga siendo válido, pero al menos detiene el error más fácil, no crea una copia y no necesita
nums
ser creado de una manera especial (por ejemplo, comostd::shared_ptr
o lostd::weak_ptr
hace).std::scoped_lock
tomar una referencia al mutex sería un ejemplo, y uno donde ptr único / compartido / débil realmente no se desea. A menudostd::mutex
, solo será un miembro básico o una variable local. Aún debe tener mucho cuidado, pero en estos casos generalmente es fácil determinar la duración de la vida.std::weak_ptr
es otra opción para no ser propietario, pero luego obliga a la persona que llama a usarshared_ptr
(y, por lo tanto, también a la asignación de montón), y a veces eso no es deseable.Si una copia está bien, eso simplemente evita el problema.
Si
Woop
debe tomar posesión, pase como un valor r y mueva (y evite los problemas de puntero / referencia por completo), o useunique_ptr
si no puede mover el valor en sí o si desea que el puntero siga siendo válido.O si se comparte la propiedad, puede usarlo
shared_ptr
para todo, y se eliminará junto con la referencia final, pero esto puede hacer que el seguimiento de los ciclos de vida de los objetos se vuelva muy confuso si se usa en exceso.fuente
Puede usar
template programming
yarrays
si desea tener un objeto que contenga unconst
contenedor. Debido alconstexpr
constructor yconstexpr arrays
lograsconst correctness
ycompile time execution
.Aquí hay una publicación que puede ser interesante: std :: mover un vector constante
Ejecutar código
Salida:
fuente
std::array
este, se garantiza que esto se copiará, incluso si un movimiento estuviera disponible de otra manera. Además de esowooping1
ywooping2
no son del mismo tipo, que es menos que ideal.