es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Llame al destructor de una clase de plantilla, se espera el nombre de la clase antes del token ‘(’

Tengo una situación excepcional donde necesito llamar al destructor de una clase para liberar la memoria de la unión. No podemos usar aún std::variant. La clase en la unión está basada en plantillas y se define de manera similar a:

template<class TYPE>
class BaseTemplate
{
  public:
    BaseTemplate() = default;
    ~BaseTemplate() = default;

<pre><code>// Otros funciones útiles
</code></pre>

private:
    TYPE value;
}
<code>
Ahora definimos diferentes tipos con `using`:
</code>cpp
using X = BaseTemplate<int>;
// Otras definiciones de `using`
<code>
En una situación anterior, `X` era una clase derivada de `BaseTemplate`.
</code>cpp
class X : public BaseTemplate<int>
{ 
  X() = default;
  ~X() override = default; // En este caso, ~BaseTemplate era virtual.

// Nada útil, así que nos gustaría eliminar esta clase.
};
<code>
En la situación anterior, podíamos llamar al destructor de esta forma:
</code>cpp
X variableX;
variableX.~X();

En la nueva situación, cuando se usa using X = BaseTemplate&lt;int&gt;;, esto resulta en el error: expected class-name before ‘(’ token. Entonces, ¿cómo llamo al destructor en este caso?

Código de reproducción:


<h1>include <iostream></h1> namespace a { class Base { public: Base() = default; virtual ~Base() = default; <pre><code>virtual void foo() = 0; </code></pre> }; template<class TYPE> class BaseTemplate : public Base { public: BaseTemplate() = default; ~BaseTemplate() override = default; <pre><code>// Otras funciones útiles. void set(const TYPE&amp; v) { value = v; } TYPE get() const { return value; } void foo() final { value *= 2; } </code></pre> private: TYPE value; }; using X = BaseTemplate<int>; using Y = BaseTemplate<unsigned int>; using Z = BaseTemplate<float>; } // Fin de namespace a union XYZ { XYZ() {} ~XYZ() {} a::X variableX; a::Y variableY; a::Z variableZ; }; XYZ xyz; int main() { // Operador nuevo en el lugar para inicializar x new(&xyz.variableX) a::X; <pre><code>xyz.variableX.set(1); xyz.variableX.foo(); std::cout &lt;&lt; &quot;Resultado: &quot; &lt;&lt; xyz.variableX.get() &lt;&lt; std::endl; xyz.variableX.~X(); </code></pre> }
Tags:  ,

Answer

  1. Avatar for davy.ai

    Para llamar al destructor de una clase en esta situación, necesitamos especificar el nombre completo de la clase, el cual incluye el argumento de plantilla. Por lo tanto, el destructor debería ser llamado de la siguiente manera:

    xyz.variableX.~BaseTemplate<int>();
    

    Esto especifica el argumento de plantilla “int” para la clase “BaseTemplate”. Alternativamente, podríamos usar un typedef o una declaración using para proporcionar un nombre más corto para la clase:

    using XT = BaseTemplate<int>;
    //...
    XT& variableX = xyz.variableX;
    variableX.set(1);
    variableX.foo();
    std::cout << "Resultado: " << variableX.get() << std::endl;
    
    variableX.~XT();
    

    De esta manera, el destructor puede ser llamado simplemente como variableX.~XT();, haciendo que el código sea más fácil de leer y mantener.

Comments are closed.