析构函数的异常调用

Unusual calling of destructor

本文关键字:调用 异常 析构函数      更新时间:2023-10-16

我在实例化类中的结构时遇到了一个奇怪的问题,在构造中它调用析构函数(多次),甚至调用父对象析构函数。

带结构的类:

class Model {
public:
     struct StepModelIO {
         StepModelIO(Model model, ...) {DoConstruction(Model model, ...);}
         StepModelIO(const StepModelIO &other) {DoConstruction(Model model, ...); }
         ~StepModelIO() {}
         DoConstruction() {
             ...
         }
    }
    Model(...) {
       ...
    }
    Model(const Model &other) {DoConstruction(...);}
    ~Model() {
        ...
    }
private:
    DoConstruction(...) {
    }
}

调用函数:

void main() {
    Model::StepModelIO stepArgs = Model::StepModelIO(...);
}

生成的调用集,其中"对象"是StepModelIO,"父"是Model

  1. 使用复制构造函数构造父项
  2. 构造对象
  3. 销毁父级
  4. 使用复制构造函数构造对象
  5. 使用复制构造函数构造父项
  6. 构造对象
  7. 销毁父级
  8. 析构对象
  9. 销毁对象(再次...
  10. 销毁父级

不出所料,在这一切发生后,由此产生的结构(StepModelIO)的状态并不好,路径看起来很荒谬。我像这样放置结构,以便在父模型对象上使用相同的泛型,这可能会解释一些问题。

尝试(也许天真地)在构造函数和析构函数上使用"三法则",有可能我把它搞得很糟糕。

编辑:完整代码

template<typename U, typename V>
class Model{
public:
    struct StepModelIO {
        Model<U, V> model;
        U u;
        V v;
        StepModelIO() {}
        StepModelIO(Model<U, V> model, U u, V v) {
            this->model = model;
            this->u = u;
            this->v = v;
        }
        StepModelIO (const StepModelIO &other) {
            StepModelIO(other.model, other.u, other.v);
        }
        ~StepModelIO() {
        }
    };
    Model(char * libraryPath) {DoConstruction(libraryPath);}
    Model() {}
    Model (const Model &other) {
        DoConstruction(other.m_LibraryPath);
    }
    ~Model() {
        this->Stop();
    }
    void Init() {
        if (!this->m_Initialised) {
            this->ModelInit();
            m_Initialised = true;
        }
    }
    void Stop() {
        if (this->m_Initialised) {
            this->ModelStop();
            m_Initialised = false;
        }       
    }
    void Restart() {
        this->ModelRestart();
    }
    void Step(U u, V v) {
        ModelStep(u, v);
    }
private:
    char* m_LibraryPath;
    HINSTANCE m_ModelDLL;
    bool m_Initialised;
    typedef int (__cdecl * EmptyModelFunctionPointer)(); // Interpret integer as C code pointer named 'EmptyModelFunctionPointer'
    typedef int (__cdecl * ModelFunctionPointer)(U u, V v);
    EmptyModelFunctionPointer ModelInit;
    EmptyModelFunctionPointer ModelStop;
    EmptyModelFunctionPointer ModelRestart;
    ModelFunctionPointer ModelStep;
    virtual void DoConstruction(char * libraryPath){
        this->m_Initialised = false;
        this->m_LibraryPath = libraryPath;
        this->m_ModelDLL = LoadLibrary(libraryPath);
        this->ModelInit = GetFunction<EmptyModelFunctionPointer>(m_ModelDLL, "Init");   
        this->ModelStop = GetFunction<EmptyModelFunctionPointer>(m_ModelDLL, "Stop");
        this->ModelRestart = GetFunction<EmptyModelFunctionPointer>(m_ModelDLL, "Restart");
        this->ModelStep = GetFunction<ModelFunctionPointer>(m_ModelDLL, "Step");
    }
    template<typename pointerType>
    pointerType GetFunction(HINSTANCE modelLibrary, char * functionName){
        return (pointerType)GetProcAddress(HMODULE (modelLibrary),functionName);
    }
};

访客:

StepModelIO<Type_1*, Type_2*> stepArgs = StepModelIO<Type_1*, Type_2*>(newModel, &a, &b[0]);

您正在按值传递事物,这将导致临时对象被构造和破坏。改为通过常量引用传递它们。

改变

  StepModelIO(Model model, ...) 

  StepModelIO(const Model &model, ...) 

您现在已更改代码。所以你真的想要这个,我想。

 StepModelIO(const Model<U, V> &model, const U &u, const V &v)

我注意到类内部有 tat StepModelIO你有一个成员Model<U, V> model;所以对于类的每个实例StepModelIO模型的析构函数也将被计算; 第一~StepModelIO()和第二~Model<U, V>()

所以给定你提供的代码:

Model::StepModelIO stepArgs = Model::StepModelIO(...);

这有两个类型为 StepModelIO 的对象。一个是右侧的 on(右值),第二个是 stepArgs .

首先调用右侧析构函数,结果为:

1: Destruct StepModelIO

2:Destruct Model

当 stepArgs 的破坏发生时:

3: Destruct StepModelIO

4:Destruct Model