2012-03-22 36 views
2

取这两个类如:让本地变量引用其他局部变量有危险吗?

struct Owned { 
    Owned() : i() { } 

    void print() { cout << ++i << endl; } 

    int i; 
}; 

struct Owner { 
    Owner(Owned& o) : o(o) { } 

    Owned& o; 

    ~Owner() { o.print(); } 
}; 

它是危险的这种方式来使用它们呢?

int main() { 
    Owned owned; 
    Owner owner(owned); 
} 

看来,这取决于它们的破坏,这可能导致owner析构函数来调用一个被毁坏的owned功能的顺序。是否定义了销毁局部变量的顺序,以及如何处理两个实例互相引用的情况?

请原谅我,如果这是常识,我还没有读过关于它的任何地方。

回答

5

局部变量按照与创建相反的顺序销毁。在你的情况下,你很好,因为owner将永远销毁owned之前。

§6.6 [stmt.jump] p2

在从范围(但是完成)退出,与已经构建在范围在其构造的相反的顺序被破坏自动存储持续时间(3.7.3)对象。

但是,如果您可以在施工后重新分配拥有的成员,则必须小心。

你怎么能让两个实例互相引用工作?

不要让它们在析构函数中互相访问。或者先清楚究竟谁会被首先销毁,也许会有一个回调或标志被通过。例如:

struct two; 
struct one{ 
    two* other; 

    one(two* o = nullptr) : other(o) {} 
    ~one(){ if(other) other.other = nullptr; } 
}; 

struct two{ 
    one* other; 
    two(one* o = nullptr) : other(o) {} 
    ~one(){ if(other) other.other = nullptr; } 
}; 

这将确保两个对象从不引用不存在的引用。

相互引用的对象是非常罕见的。

+0

好吧,这基本上是我在想什么。谢谢。 – 2012-03-22 17:38:27

+0

通过“让两个实例互相引用”我假定你的意思是'拥有'和'所有者'都包含对立类型的成员引用。这样做,你不能真的。但那是因为引用不能在创建后重新分配给新的对象。如果你只是a)切换到指针,b)在构造函数之外执行任务(将你从特定的时间问题中解脱出来),那么你可以完全掌握什么可以达到什么目的。但具有很大的权力....:p – 2012-03-22 17:43:39

+0

@迈克尔:只需分配给建设后的“其他”成员。我已经有指针了。 '一个o;两个t(&o); o.other =&t;' – Xeo 2012-03-22 17:44:40

0

这是安全的,本地对象以创建它们的相反顺序销毁。

+0

那么如果我以另一种方式声明他们,行为是不确定的?那么第二个问题呢? – 2012-03-22 17:29:32

+0

@SethCarnegie:你如何以另一种方式宣布他们? – Naveen 2012-03-22 17:32:54

1

Owner实际上并不拥有owned它只是有一个引用它,所以当它被销毁的时候,拥有的析构函数将不会被调用。

+0

这忽略了问题的关键。 – 2012-03-22 17:30:10

+0

担心的是'拥有'将在'所有者'之前被销毁,因此后者的析构者将访问一个悬而未决的参考。 – Xeo 2012-03-22 17:30:18

+0

对不起,没睡过 – 111111 2012-03-22 17:37:15

1

无论如何,你写的东西并不危险,C++中相同范围内的变量会以定义的(反向排序的方式)被销毁。然而,像这样的事情是危险的,但是,

int main() { 
    Owner owner(); 
    { 
     Owned owned; 
     owner.setOwned(owned); 
    } 

    owner.doSomethingWithOwned(); 
} 

因为拥有不再存在,它被迫超出范围。这也适用于将局部变量设置为堆中对象的引用。

+0

函数没有名为'setOwned'的方法:) – 2012-03-22 17:35:55

+0

你是对的。但是,如果您将setOwned图像以类似的方式复制到构造函数中,您可以看到不应该引用超出范围的对象(因为它不存在)。 – 2012-03-22 17:46:05

+0

是的,除了函数声明外,答案是正确的(AFAIK)。 – 2012-03-22 18:02:16