recesion proxima protegerse mundial inminente economico economica crisis como colapso c++ sdk

c++ - protegerse - proxima crisis economica mundial



Construcción de dos fases en C++ (10)

¿Por qué se usaría este "bifásico" y qué beneficios hay?

Este idioma se usa por dos razones:

  • para separar la inicialización en dos partes diferentes: la parte que siempre es estable y no fallará (se deja en el constructor) y la parte que puede fallar (la función de construcción separada).

Esta expresión ha sido utilizada en el pasado antes de que el uso de excepciones estuviera estandarizado en el lenguaje, y por los diseñadores de la biblioteca que no entendían (o por alguna razón no querían usar) las excepciones.

Todavía lo encontrará en el código heredado / compatible con versiones anteriores (por ejemplo, MFC).

  • para implementar "construcción virtual". Básicamente, usted declara su función miembro de Construction como virtual (pura) y permite que las clases especializadas la reemplacen. Esto es casi siempre [1] un signo o diseño deficiente (puede y debe implementar su código para que no necesite este modismo).

[1] - "casi siempre" significa aquí que no veo ninguna razón para hacerlo pero me puede estar perdiendo algo :).

Como parte de mis tareas, he estudiado un kit de desarrollo que utiliza la construcción "bifásica" para las clases de C ++:

// Include Header class someFubar{ public: someFubar(); bool Construction(void); ~someFubar(); private: fooObject _fooObj; }

En la fuente

// someFubar.cpp someFubar::someFubar : _fooObj(null){ } bool someFubar::Construction(void){ bool rv = false; this->_fooObj = new fooObject(); if (this->_fooObj != null) rv = true; return rv; } someFubar::~someFubar(){ if (this->_fooObj != null) delete this->_fooObj; }

¿Por qué se usaría este "bifásico" y qué beneficios hay? ¿Por qué no simplemente crear una instancia de la inicialización del objeto dentro del constructor real?


A veces tienes que usar C ++ sin excepciones habilitadas. En esa situación, la falta de un valor de retorno de un constructor hace que la vida sea difícil, por lo que tiene una función de construcción explícita que puede probar para el éxito en su lugar.


Ciertamente no sería un fan de esta construcción de dos pasos. Hay muchas otras formas de evitar una excepción / error en un constructor. En primer lugar, cualquier compilador de C ++ que valga su peso debería ser capaz de arrojar una excepción desde un constructor y permitir que se capture apropiadamente.

Otra solución sería tener un código de error interno similar al enfoque posix errno . Y la persona que llama podría consultar este código de error a través de una llamada a un miembro de la clase. IIR Windows tiene algo como esto con la función GetLastError .


Esto es útil cuando tiene que darle al usuario (de su clase) más control sobre la asignación / desasignación de recursos. Por ejemplo, piense en una clase Socket. El usuario transfiere los parámetros de host y puerto al constructor y puede retrasar la "apertura" real de los sockets (es decir, asignando el objeto SOCKET de bajo nivel) a un momento posterior. También es posible que desee cerrar y volver a abrir el zócalo a voluntad. La construcción en dos fases (o Inicialización diferida ) facilita esto. Tal interfaz de socket se verá así:

class Socket { public: Socket (const std::string& host, int port) : host_(host), port_(port), sock_(NULL) { } ~Socket () { close (); } void open () throw (NetworkException&) { sock_ = new_low_level_socket (host_, port_); } void close () { if (sock_) { close_low_level_socket (sock_); sock_ = NULL; } } // private members }; // Usage: ing main () { Socket sock ("www.someurl.com", 80); sock.open (); // do something with sock sock.close (); // do something else sock.open(); // do something with sock return 0; // sock is closed by destructor. }

Por cierto, este modismo no es un reemplazo para evitar que las excepciones sean lanzadas desde el constructor. Si el constructor falla, lanza una excepción. Para obtener más información, consulte estas preguntas frecuentes sobre BS y la entrada en C ++ - FAQ-Lite .


La fuente dada es extraña en extremo.

Si es C ++, entonces new no puede devolver 0 y debe arrojar una excepción.

Si es algo no muy diferente de C ++ donde los nuevos retornos 0 al fallar (tales cosas se sabe que existen), entonces Construction es equivalente a:

bool someFubar::Construction(){ // no need for void in C++, it''s not C delete _fooObj; // nothing stops this getting called twice! _fooObj = new fooObject(); // no need for this->, it''s not Python return _fooObj; // non-zero is true } someFubar::~someFubar(){ delete fooObj; // it''s OK to delete NULL in C++. }

Ahora tenemos un problema: si se llama a Construcción dos veces, la construimos de nuevo y devolvemos la verdad como antes, no la construimos de nuevo y devolvemos la verdad tal como está construida, o no la construimos de nuevo y devolvemos falsa ya que es un error para construir algo dos veces?

A veces, por ejemplo, para las clases que gestionan recursos externos, es posible que desee implementarlos como una máquina de estado que cree, luego asigne el recurso. Esto es razonable cuando un recurso puede dejar de ser válido, por lo que tendrá que verificar las operaciones que realiza en él de todos modos. Proporcionar una conversión del tipo a bool es el patrón que se usa en la biblioteca estándar para dichos recursos. Normalmente, debe construir un objeto de una vez y esperar que sea válido.


No hay una buena razón para hacer esto: evitar. El autor original del código probablemente simplemente no sabía lo que estaban haciendo.


Una razón para hacer esto podría ser que los constructores no devuelven ningún valor. Algunas personas prefieren hacer una función Crear como que se debe invocar después de la instanciación de objetos. En caso de que no utilice la excepción porque crean mucho código (especialmente en el mundo integrado), es imposible usar solo el constructor porque no ofrece ninguna garantía (como dije, no puede devolver ningún valor).

Otra técnica que vi fue algo como esto:

XObject* o = new XObject(); o->IsOk();

Básicamente hace la construcción dentro del constructor y mantiene el resultado de la operación dentro de una variable, no de espacio eficiente.


Mi respuesta desde las trincheras es que la construcción en dos fases, especialmente cuando se trata de la inicialización del hardware, es imprescindible. En el mundo real, si un objeto puede fallar al construir o controlar algo, entonces un escenario de pesadilla simplemente está por suceder.

Si las clases de control de hardware inicializan el hardware en sus constructores (que está conectado a cosas que pueden doblarse, plegarse, girar o mutilar humanos), entonces toda la arquitectura de la aplicación debe cambiar para acomodar eso. Cambia porque no puedo componer mis objetos de la manera que me gustaría. Tal vez quiero un "controlador maestro" que incorpore todos los subcontroladores. Quiero libertad para construirlos en cualquier momento. Los objetos que pueden fallar al construir o energizar hardware cuando están construidos lanzan una gran llave inglesa en las obras. En esos casos, tengo que diferir la creación de objetos hasta la hora correcta. Eso significa punteros a los objetos, que aún pueden ser nulos, y que te obliga a tratar con punteros nulos para objetos importantes. Odio que me obliguen a hacer eso.

En mi visión del mundo, quiero que mis constructores sean inofensivos, siempre funcionen sin falta, simplemente inicialicen todas sus propiedades (y tal vez les apliquen algunos argumentos). Y nada más. Solo prepare el objeto de modo que pueda construirlo, o aplique referencias a ellos cuando y donde quiera. Manejaré la ''conexión'' o ''inicialización'' de las piezas importantes en el momento y lugar que elija, preferiblemente con un método abierto (...) o init (...).


Otros aquí han mencionado el caso en el que el método Construction () es virtual. Una situación en la que esto puede jugar un papel útil es en la deserialización de un gráfico de objetos (el RogueWave Tools.h ++ utilizó esta técnica IIRC):

  • una fábrica asigna la subclase concreta en función de alguna representación dinámica de su tipo, tal vez indirectando a través de un conmutador, una matriz o un diccionario de algún tipo, con lo cual ...
  • ... da la vuelta rápidamente y le pide al objeto recién construido que deserialice sus propios contenidos, restaurando así su propio estado, como solo él sabe, llamando al método virtual de Construcción (), tal vez pasándole un flujo de entrada o lo que sea para leer de.

Otro uso para esta técnica se describe aquí : como un medio de factorizar código común de un número de constructores sobrecargados.


Un documento sobre la construcción de dos fases .

La idea es que no se puede devolver un valor de un constructor para indicar un error. La única forma de indicar la falla del constructor es lanzar una excepción. Esto no siempre es deseable, sobre todo porque la seguridad de excepciones es un tema muy complejo.

Entonces, en este caso, la construcción se divide: un constructor que no arroja, pero tampoco inicializa por completo, y una función que realiza la inicialización y puede devolver una indicación de éxito o fracaso sin (necesariamente) arrojar excepciones.