本文介绍了当委托构造函数抛出时,内存是否自动回收?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

接下来:

  c> $   

如果由 new 调用的构造函数抛出一个异常,那么由 new 分配的内存将被自动释放。

对象初始化的任何部分描述包括构造函数调用和传递给构造函数的表达式的计算。



此外,这个行为在C ++ 98标准中有相同的规定[C ++ 98 5.4.3 / 17]。委托构造函数唯一的区别是,如果你的心理模型以前是基于完全构造的对象。






在第一个例子中:

  new X(5); 

事件顺序为:




  • 分配函数

  • X(int)调用




      • X(int)会抛出异常



      • 〜X()


    • 通过异常退出X(int)

    • 由于对象初始化失败而调用的释放函数

    • 异常继续正常传播



    使用第二个示例

      new X(5.0); 




  • 分配函数

  • X(double)

  • X(double)失败,但异常

  • 异常继续正常传播



您可以通过替换分配和释放函数来观察此行为:

  #include< iostream> 
#include< cstdlib>
#include< stdexcept>
#include< new>

void * operator new(std :: size_t s){
if(void * ptr = std :: malloc(s)){
std :: cout< ; allocation\\\
;
return ptr;
}
throw std :: bad_alloc {};
}

void operator delete(void * ptr)noexcept {
if(ptr){
std :: cout< deallocation\\\
;
std :: free(ptr);
}
}

struct S {
S(){};
S(int):S {} {throw std :: exception(); }
S(double){throw std :: exception(); }
〜S(){std :: cout<< destructor\ n; }
};

int main(){
std :: cout< test 1 \\\
;
try {
new S(1);
} catch(...){
std :: cout< exception caught\\\
;
}

std :: cout<< test 2\\\
;
try {
new S(1。);
} catch(...){
std :: cout< exception caught\\\
;
}
}

此程式的正确输出为:

  test 1 
分配
destructor
deallocation
捕获到异常
test 2
分配
deallocation
捕获异常


Following on from this: Is the destructor called when a delegating constructor throws?

class X
{
public:
    X()       {};
    X(int)    : X() { throw std::exception(); }
    X(double)       { throw std::exception(); }
    ~X();
};

What about dynamic memory? Normally an exception in the constructor means the object was not fully constructed and thus the memory is cleanedup and not lost.

But the argument in the previous question is that the object is fully constructed (or fully initialized) after the delegate completes. How does this affect reclaiming the memory? I would hope that memory is still cleanedup!

int main()
{
    new X(5);        // new called
                     // delete called because delegate completed.
                     // I assume:
                     //      Memory re-claimed (because constructor did not complete)
                     //      I assume the C++11 standard adjusted to compensate.
                     //      As a constructor did complete.
}

Compared too:

int main()
{
    new X(5.0);      // new called
                     //    Delete **NOT** called
                     // Memory re-claimed (because constructor did not complete)
}

If the memory is cleaned up, then the definition of when the memory is cleanup needs to be altered from C++03 spec. How is the behavior changed?

解决方案

If the constructor called by new throws an exception then the memory allocated by new is automatically deallocated. Delegating constructors change nothing in this regard.

The 'any part of the object initialization' described includes both the constructor calls and evaluation of the expressions passed to the constructor.

Also, this behavior is specified identically in the C++98 standard [C++98 5.4.3/17]. The only difference delegating constructors make is if your mental model was previously based on the object being completely constructed or not. Given delegating constructors that's no longer equivalent to the actual specification of when deallocation occurs.


In your first example:

new X(5);

The order of events is:

  • allocation function called
  • X(int) called
    • X() called (and exits successfully)
    • X(int) throws an exception
    • ~X() called
  • X(int) exits via exception
  • deallocation function called because object initialization failed
  • exception continues to propagate normally

With the second example

new X(5.0);

  • allocation function called
  • X(double) called
  • X(double) fails with an exception
  • deallocation function called because object initialization failed
  • exception continues to propagate normally

You can observe this behavior by replacing the allocation and deallocation functions:

#include <iostream>
#include <cstdlib>
#include <stdexcept>
#include <new>

void *operator new(std::size_t s) {
    if (void *ptr = std::malloc(s)) {
        std::cout << "allocation\n";
        return ptr;
    }
    throw std::bad_alloc{};
}

void operator delete(void *ptr) noexcept {
    if (ptr) {
        std::cout << "deallocation\n";
        std::free(ptr);
    }
}

struct S {
    S() {};
    S(int) : S{} { throw std::exception(); }
    S(double) { throw std::exception(); }
    ~S() { std::cout << "destructor\n"; }
};

int main() {
    std::cout << "test 1\n";
    try {
        new S(1);
    } catch(...) {
        std::cout << "exception caught\n";
    }

    std::cout << "test 2\n";
    try {
        new S(1.);
    } catch(...) {
        std::cout << "exception caught\n";
    }
}

The correct output of this program is:

test 1
allocation
destructor
deallocation
exception caught
test 2
allocation
deallocation
exception caught

这篇关于当委托构造函数抛出时,内存是否自动回收?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-16 03:40