Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Tip
Use punteros inteligentes en lugar de manual AddRef/Release. El recuento manual de referencias es la principal fuente de errores COM (objetos perdidos, uso después de la liberación, doble liberación). El código moderno de C++ debe usar punteros inteligentes que controlen el recuento de referencias automáticamente:
#include <wrl/client.h> // Microsoft::WRL::ComPtr
// ComPtr automatically calls AddRef on copy and Release on destruction
Microsoft::WRL::ComPtr<IStream> stream;
HRESULT hr = CreateStreamOnHGlobal(nullptr, TRUE, &stream);
if (FAILED(hr)) return hr;
// Pass to another interface — use .Get() for raw pointer
// Note: operator& on ComPtr asserts if it already holds a value.
// Use .ReleaseAndGetAddressOf() if the ComPtr may be non-null.
Microsoft::WRL::ComPtr<IUnknown> unknown;
hr = stream.As(&unknown); // Safe QueryInterface — no manual Release needed
Alternativas:
-
winrt::com_ptr<T>: puntero inteligente de C++/WinRT (requiere C++17, se integra con proyecciones de WinRT) -
wil::com_ptr_nothrow<T>— bibliotecas de implementación de Windows (alternativa sin excepciones)
Las reglas manuales AddRef/Release que se describen a continuación siguen siendo relevantes para comprender cómo funciona COM internamente y para implementar servidores COM, pero el código de cliente rara vez debe llamar a estos métodos directamente.
En los sistemas de objetos tradicionales, el ciclo de vida de los objetos (es decir, los problemas relacionados con la creación y eliminación de objetos) se controlan implícitamente por el lenguaje (o el tiempo de ejecución del lenguaje) o explícitamente por los programadores de aplicaciones.
En un sistema en evolución, construido de forma descentralizada y compuesto por componentes reutilizados, ya no es cierto que ningún cliente, ni siquiera ningún programador, siempre sepa cómo gestionar el ciclo de vida de un componente. Para un cliente con los privilegios de seguridad adecuados, todavía es relativamente fácil crear objetos a través de una solicitud simple, pero la eliminación de objetos es otra cuestión completamente. No es necesariamente claro cuando ya no se necesita un objeto y se debe eliminar. (Los lectores familiarizados con los entornos de programación con recolección de basura, como Java, pueden no estar de acuerdo; sin embargo, los objetos de Java no traspasan los límites de la máquina ni siquiera los del proceso y, por lo tanto, la recolección de basura está restringida a los objetos que existen dentro del espacio de un único proceso. Además, Java obliga a utilizar un único lenguaje de programación.) Incluso cuando el cliente original ha terminado de usar el objeto, no puede simplemente desactivarlo, porque algún otro cliente u otros clientes podrían seguir teniendo una referencia a él.
Una manera de asegurarse de que un objeto ya no es necesario es depender completamente de un canal de comunicación subyacente para informar al sistema cuando todas las conexiones a un objeto entre procesos o entre canales han desaparecido. Sin embargo, los esquemas que usan este método son inaceptables por varias razones. Un problema es que podría requerir una diferencia importante entre el modelo de programación entre procesos y entre redes y el modelo de programación de un solo proceso. En el modelo de programación entre procesos y entre redes, el sistema de comunicación proporcionaría los enlaces necesarios para la administración de la duración de objetos, mientras que en el modelo de programación de un solo proceso, los objetos se conectan directamente sin ningún canal de comunicación intermedio. Otro problema es que este esquema también podría dar lugar a una capa de software proporcionado por el sistema que interferiría con el rendimiento de los componentes en el caso en proceso. Además, un mecanismo basado en la supervisión explícita no tiende a escalarse hacia muchos miles o millones de objetos.
COM ofrece un enfoque escalable y distribuido para este conjunto de problemas. Los clientes indican a un objeto cuándo lo usan y cuándo han terminado, y los objetos se eliminan a sí mismos cuando ya no son necesarios. Este enfoque exige que todos los objetos mantengan un recuento de sus propias referencias. Los lenguajes de programación, como Java, que inherentemente tienen sus propios esquemas de administración de la vida útil, como la recolección de elementos no utilizados, pueden usar el recuento de referencias de COM para implementar y usar objetos COM internamente, lo que permite al programador evitar tratarlo.
Al igual que una aplicación debe liberar la memoria que ha asignado una vez que esa memoria ya no se utilice, un cliente de un objeto es responsable de liberar sus referencias al objeto cuando este ya no sea necesario. En un sistema orientado a objetos, el cliente solo puede hacerlo proporcionando al objeto una instrucción para liberarse.
Es importante que un objeto se desasigne cuando ya no se use. La dificultad radica en determinar cuándo es adecuado desasignar un objeto. Esto es fácil con variables automáticas (las asignadas en la pila): no se pueden usar fuera del bloque en el que se declaran, por lo que el compilador los desasigna cuando se alcanza el final del bloque. En el caso de los objetos COM, que se asignan dinámicamente, es necesario que los clientes de un objeto decidan cuándo ya no necesitan usar el objeto, especialmente objetos locales o remotos que pueden estar en uso por varios clientes al mismo tiempo. El objeto debe esperar hasta que todos los clientes terminen con él antes de liberarse. Dado que los objetos COM se manipulan a través de punteros de interfaz y los pueden usar objetos en procesos diferentes o en otras máquinas, el sistema no puede realizar un seguimiento de los clientes de un objeto.
El método de COM para determinar cuándo es adecuado desasignar un objeto es el recuento manual de referencias. Cada objeto mantiene un recuento de referencias que realiza un seguimiento del número de clientes conectados a él, es decir, cuántos punteros existen a cualquiera de sus interfaces en cualquier cliente.
Para obtener más información, consulta los temas siguientes:
Temas relacionados