www whirlpool washing quiet partner machine lavadora espaƱol dishwasher c++ c++11 undefined-behavior rvalue-reference

c++ - quiet - whirlpool washing machine repair manual pdf



Objeto pasado a std:: move pero no movido desde? (2)

Es una advertencia espuria de su herramienta de análisis estático.

  1. ¿Esto funciona?

Sí, MaybeConsume está haciendo lo que dice el comentario. Solo toma posesión de su argumento cuando some condition es verdadera (asumiendo que Consume realmente mueve la construcción / asignación de su argumento).

std::move es, de hecho, solo una fantasía static_cast<T&&> así que MaybeConsume(std::move(a)) no transfiere la propiedad, simplemente está vinculando una referencia al parámetro MaybeConsume .

  1. ¿Es UB?

No, no estás haciendo uso de a si MaybeConsume indica que ha asumido la propiedad de su argumento.

  1. Es std::move a ??? un no-op?

Bueno, es un no-op porque es solo un static_cast , pero si static_cast preguntar si es innecesario, entonces no, no lo es. Dentro del cuerpo de MaybeConsume , a es un lvalue porque tiene un nombre . Si la firma de Consume es void Consume(A&&) , entonces el código no se compilará sin ese std::move .

Por el ejemplo de uso que ha mostrado, parece que no debe llamar a MaybeConsume con un argumento prvalue, ya que la persona que llama debería presumiblemente usar el argumento de alguna otra manera si la función devuelve false . Si eso es cierto, entonces debería cambiar su firma a bool MaybeConsume(A&) . Esto probablemente hará feliz a su herramienta de análisis estático porque le permitiría escribir if (!MaybeConsume(a)) .

Estoy revisando un código como este, donde A es un tipo movible:

// Returns true exactly when ownership of a is taken bool MaybeConsume(A&& a) { if (some condition) { Consume(std::move(a)); // ??? return true; } return false; } // ... elsewhere ... A a; if (!MaybeConsume(std::move(a))) { a.DoSomething(); // !!! }

Nuestra herramienta de análisis estático se queja de que se usa después de ser movido (en !!! ). IIUC std::move es solo un static_cast , y el objeto a no se static_cast realmente hasta que se llame a un constructor de movimiento u operador de asignación (presumiblemente en Consume ). Suponiendo que MaybeConsume cumpla con el contrato en el comentario,

  1. ¿Esto funciona?
  2. ¿Es UB?
  3. Es std::move a ??? un no-op?

(Probablemente este caso en particular puede ser refactorizado para evitar la sutileza, pero todavía me gustaría pedir mi propio entendimiento).


Para comprender por qué la herramienta de análisis estático genera una advertencia, uno debe pensar de la manera en que lo hace un analizador estático. Cuando ve un trozo de código como el siguiente:

A a; fun(std::move(a); a.method();

No está claro qué podría pasar dentro de la llamada de diversión (). Para llevar a cabo con éxito el método () en un depende de algunos requisitos previos que se cumplen, que no puede (o ya no) se mantiene después de la llamada de la diversión (). Si bien el programador puede saber que es seguro llamar al método (), el analizador no lo hace, por lo que genera una advertencia.

Lo siguiente es solo mi propia opinión. Es más seguro asumir que la propiedad de a se toma en su totalidad por diversión (). Para evitar confusiones, es mejor imponer un estilo de préstamo y devolución. Pensando en ello como si un amigo le prestara un libro, usted no puede (no puede) usar ese libro hasta que se devuelva. Por lo tanto, nunca se arriesgue accidentalmente a invocar un objeto que debería estar "muerto" para entonces.

Vea el siguiente código de demostración:

#include <iostream> #include <utility> #include <tuple> #include<cassert> struct A { public: int *p; public: A() { p = new int(); assert(p != nullptr); std::cout << p << std::endl; std::cout << "default constrctor is called" << std::endl; } A(const A&) = delete; A& operator=(const A&) = delete; A(A&& _a): p(_a.p) { _a.p = nullptr; std::cout << p << std::endl; std::cout << "move constructor is called" << std::endl;; } A& operator=(A&& _a) { std::cout << "move assignment is called"<<std::endl;; p = std::move(_a.p); return *this; } void DoSomthing(){ std::cout << "do somthing is called" << std::endl; *p = 100; std::cout << "value of p is changed"<<std::endl; } }; std::tuple<A&&, bool> MaybeConsume(A&& a) { if (1==2) {//try 1==1 alternatively delete a.p; a.p = nullptr;//consume std::cout << "content consumed" << std::endl; return std::make_tuple(Consume(std::move(a)), true); } else { return std::make_tuple(std::move(a), false); } } int main() { A a; std::tuple<A&&, bool> t = MaybeConsume(std::move(a)); if (!(std::get<bool> (t))) { A a1 = std::move(std::get<A&&>(t)); a1.DoSomthing(); } return 0; }