代码之家  ›  专栏  ›  技术社区  ›  user0042

关于析构函数调用,堆栈展开是如何工作的?

c++
  •  0
  • user0042  · 技术社区  · 8 年前

    #include <iostream>
    
    struct foo {
        ~foo() {
            std::cout << "~foo()" << std::endl;
        }
    };
    
    struct bar {
        foo x;
        bar() : x() {
            throw -1;
        }
        ~bar() {
            std::cout << "~bar()" << std::endl;
        }
    };
    
    struct baz {
        ~baz() {
            std::cout << "~baz()" << std::endl;
        }
    };
    
    int main() {
        try {
            baz y;
            bar z;
        } // Destructor is called for everything fully constructed up to here?
        catch(...) {
        }
    }
    

    ~foo()
    ~baz()
    

    很明显 bar 的析构函数未调用。

    这对任何一种计划在2010年发布的资源分配意味着什么

    struct bar {
        CostlyResource cr;
        bar() {
            cr.Open(); // Aquire resource
    
            // something else throws ...
            throw -1;
        }
        ~bar() {
            if(cr.IsOpen()) {
                cr.Release(); // Free resource
            }
        }
    };
    

    为了实现异常安全,我可以做些什么来确保 酒吧

    2 回复  |  直到 8 年前
        1
  •  2
  •   user0042    8 年前

    为了实现异常安全,我可以做什么来确保正确释放bar的资源成员?

    你可以 catch

    struct bar {
        CostlyResource cr;
        bar() {
            try { // Wrap the whole constructor body with try/catch
                cr.Open(); // Aquire resource
    
                // something else throws ...
                throw -1;
             }
             catch(...) { // Catch anonymously
                 releaseResources(); // Release the resources
                 throw; // Rethrow the caught exception
             }
        }
        ~bar() {
            releaseResources(); // Reuse the code ro release resources
        }
    private:
        void releaseResources() {
            if(cr.IsOpen()) {
                cr.Release(); // Free resource
            }
        }
    };
    

    here


    因为这是在构造函数中进行动态内存分配时经常遇到的问题,例如

    class MyClass {
         TypeA* typeAArray;
         TypeB* typeBArray;
    public:
         MyClass() {
             typeAAArray = new TypeA[50];
             // Something else might throw here
             typeBAArray = new TypeB[100];
         }
         ~MyClass() {
             delete[] typeAAArray;
             delete[] typeBAArray;
         }
    };
    

    std::vector<TypeA> , std::vector<TypeB> ),或智能指针(例如。 std::unique_ptr<TypeA[50]> ).

        2
  •  1
  •   M.M    8 年前

    直到构造函数完成,对象的生存期才开始。如果从构造函数抛出异常,则不会调用该对象的析构函数。当然,任何已经构造的子对象都将按与构造相反的顺序被破坏,正如您在第一个示例中看到的那样 ~foo()

    第二个示例中的代码不是异常安全的。 CostlyResource 设计糟糕-它自己的析构函数应该释放资源。那么你的代码就正确了。

    struct SafeCostlyResource : CostlyResource
    {
        ~SafeCostlyResource()
        {
            if (IsOpen()) 
               Release(); 
        }
    };
    

    并将其作为 cr .