7

可以说我有两个本地对象。当函数返回时,是否保证哪个会先出作用域?

例如:

我有这样的课:

class MutexLock
{
    /* Automatic unlocking when MutexLock leaves a scope */
    public:
      MutexLock (Mutex &m)      { M.lock();   }
      ~MutexLock(Mutex &m)      { M.unlock(); }
};

这是一个非常常见的技巧,用于在超出范围时自动释放互斥锁。但是如果我在作用域中需要两个互斥锁怎么办?

void *func(void *arg)
{ 
    MutexLock m1;
    MutexLock m2;

    do_work();

}  // m1 and m2 will get unlocked here. But in what order? m1 first or m2 first?

这真的不会造成任何僵局。但在某些情况下,释放资源的顺序可能对用户有用。在那种情况下,显式而不是依赖析构函数重要吗?

另外,编译器在任何情况下都可以延迟销毁吗?我的意思是

func()

{

     {
         foo f();
     } ---------> Can compiler choose to not destroy f here, rather do it at the time when func() is returning. 
}
4

4 回答 4

10

// m1 and m2 will get unlocked here. But in what order? m1 first or m2 first?

析构函数将按构造的相反顺序调用:m2然后m1

在那种情况下,显式而不是依赖析构函数重要吗?

破坏顺序是明确指定的,因此您可以依赖它。

另外,编译器在任何情况下都可以延迟销毁吗?

不,如果是这样,那会破坏很多基于RAII的代码(你的MutexLock类就是一个很好的例子)。

于 2012-05-15T06:32:41.367 回答
4

在那种情况下,显式而不是依赖析构函数重要吗?
不,这不是必需的。
范围内对象的销毁顺序是明确定义的。
这与它们的构建顺序完全相反。


另外,编译器在任何情况下都可以延迟销毁吗?

,编译器不能,这就是RAII的目的。它提供了一种隐式清理和释放资源的机制,而无需程序员进行任何显式的手动操作。
您延迟销毁的要求与 RAII 的目的是平行的,它需要手动资源管理
如果您需要手动资源管理,您可以在堆上分配指针,new并且它们指向的对象将是有效的,除非您通过delete调用和调用它们的顺序显式取消分配它们。
当然,这样做既不建议也不鼓励这样做。

于 2012-05-15T06:44:16.233 回答
2

破坏以相反的构造顺序发生:首先m2然后m1

编译器永远不能将对象的生命周期延迟到作用域 end ( }) 之后。

于 2012-05-15T06:34:10.037 回答
0

当对象超出范围时,它总是被销毁——这不是java。f 将在您指定的地方被销毁,并且永远不会在 func 结束时被销毁。通常,析构函数的调用顺序与它们的构造顺序相反。

于 2012-05-15T06:34:46.630 回答