Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 有人能确切地解释一下,如果在堆上分配对象数组的过程中抛出异常,会发生什么情况吗?_C++_Exception_Exception Handling_New Operator - Fatal编程技术网

C++ 有人能确切地解释一下,如果在堆上分配对象数组的过程中抛出异常,会发生什么情况吗?

C++ 有人能确切地解释一下,如果在堆上分配对象数组的过程中抛出异常,会发生什么情况吗?,c++,exception,exception-handling,new-operator,C++,Exception,Exception Handling,New Operator,我定义了一个类foo,如下所示: class foo { private: static int objcnt; public: foo() { if(objcnt==8) throw outOfMemory("No more space!"); else objcnt++; } class outOfMemory { public: outOfMemory(char* msg)

我定义了一个类foo,如下所示:

class foo {
private:
   static int objcnt;
public:
   foo() {
       if(objcnt==8)
           throw outOfMemory("No more space!");
       else
          objcnt++;
   }

   class outOfMemory {
   public:
       outOfMemory(char* msg) { cout << msg << endl;}
   };

   ~foo() { cout << "Deleting foo." << endl; objcnt--;}
};
int foo::objcnt = 0;
class-foo{
私人:
静态内部对象;
公众:
foo(){
if(objcnt==8)
扔掉记忆(“没有空间了!”);
其他的
objcnt++;
}
类outOfMemory{
公众:

outOfMemory(char*msg){cout析构函数仅为完全构造的对象调用-这些对象的构造函数正常完成。只有在
new[]时引发异常时才会自动发生这种情况
正在进行中。因此,在您的示例中,析构函数将针对在
q=new foo[7]
运行期间完全构造的五个对象运行

自从<代码> No.[/COD] >代码> P<代码>代码完成,数组现在被处理到您的代码,C++运行时不再关心它了——除非您执行<代码> DEL[] [P/<代码> < < /P> > P>原子,否则将不运行析构函数。C++的分配和构造函数是正确的和异常的安全:如果代码>新的t<代码>;抛出,没有泄漏,如果<代码>新的t[n] < /C>在任何地方都沿路抛出,那么所有已经构建的东西都被销毁了。所以没有什么可担心的。 现在是离题:

<> P> <你的强>总是/ <强>必须担心的是,在任何单一的责任单位中使用不止一个<代码>新< /代码>表达式。基本上,你必须考虑任何<代码>新< /COD>表达式作为一个烫手山芋,需要被一个完全构建的、负责任的守护对象所吸收。

严格地将
new
new[]
视为库构建块:您永远不会在高级用户代码中使用它们(可能除了构造函数中的单个
new
之外),而只能在库类中使用它们

也就是说:

// BAD:
A * p = new A;
B * q = new B;  // Ouch -- *p may leak if this throws!

// Good:
std::unique_ptr<A> p(new A);
std::unique_ptr<B> q(new B); // who cares if this throws
std::unique_ptr<C[3]> r(new C[3]); // ditto
//坏:
A*p=新的A;
B*q=new B;//哎哟--*p如果抛出,可能会泄漏!
//好:
std::唯一的ptr p(新A);
std::unique_ptr q(新的B);//谁在乎这是否会引发
std::unique_ptr r(新的C[3]);//同上

另一方面:标准库容器实现了类似的行为:如果您说
resize(N)
(growing),并且在任何构造过程中发生异常,那么所有已构造的元素都将被销毁。也就是说,
resize(N)
要么将容器增长到指定的大小,要么根本不增长。(例如,在GCC 4.6中,有关异常检查范围构造的库版本,请参见
bits/vector.tcc
\u M_fill_insert()
的实现。)

在堆上声明数组时,您会得到预期的行为:

int main()
{
    try
    {
        foo   p[3];
        cout << "p in try " << p << endl;
        foo   q[7];
    }
    catch(foo::outOfMemory& o)
    {
       cout << "Out-of-memory Exception Caught." << endl;
    }
}
intmain()
{
尝试
{
foop[3];

LokiAstari:我认为OP没有真正的代码;我认为这是专门为探索
new[]
…而设计的测试代码。我不同意他明确谈论堆上的数组,而不谈论新的,OP写的是创建数组(这正好是使用new)。还有什么比可编译代码更真实呢?@Kerrek SB:事实上,我知道在代码中使用原始指针是不好的做法,最好使用RAII。但无论如何,非常感谢您的建议。您对代码意图的理解是正确的。它旨在探索新[]C++中的异常。实际上,我想问的是,如果第二个新的异常抛出,为什么P可能会泄漏。@ RialMa:因为当该范围通过异常时,代码< > >代码>丢失,所以没有办法销毁和解除<代码> *P<代码>。当一个范围退出时,所有的析构函数都会出现。如果你想到C++程序流程,那么引擎盖下面会有大量的魔法会被手工编写出来。如果数组P指向的不是堆,那么它在哪里呢?我想通过声明数组P类似于FoPp(3)。,您实际上是在堆栈上声明它。一旦抛出异常,这3个对象在堆栈展开过程中自然会被销毁。请注意,p指向的数组不在堆栈上(只有指针p)。如果您在上声明数组p,则如下所示:
foop[3]@这三个也会被破坏。@夏普:非常感谢你的回答!你说C++运行时一旦成功完成,就不再关心P。这是不是说一旦抛出异常,程序就超出P的范围,P就被简单地销毁了,而它所指向的内存就不会被带到车上去。在C++运行时?@ RialMa:完全正确。一旦代码>新[]/COM>正常完成,你的代码就负责管理数组生存期。<代码> P<代码>是一个原始指针,它有一个琐碎的析构函数,所以当它超出范围(通常或由于异常)时它将被正式销毁,但这种销毁不会对指向阵列造成任何影响,阵列将泄漏。
int main()
{
    try
    {
        foo   p[3];
        cout << "p in try " << p << endl;
        foo   q[7];
    }
    catch(foo::outOfMemory& o)
    {
       cout << "Out-of-memory Exception Caught." << endl;
    }
}
int main()
{
    try
    {
        std::vector<foo>     p(3);
        cout << "p in try " << p << endl;
        std::vector<foo>     q(7);

        // Now you can pass p/q to function much easier.

    }
    catch(foo::outOfMemory& o)
    {
       cout << "Out-of-memory Exception Caught." << endl;
    }
}