2012-05-10 114 views
3

我来到一个奇怪的段错误。原因居然使我的错误,但我还是不明白为什么一个分割故障导致这里...代码是:奇怪的段错误与unique_ptr和shared_ptr

#include <memory> 
int main(int argc, char **arv) 
{ 
    int *i = new int; 
    std::unique_ptr<int> u1(i); 
    std::unique_ptr<int> u2; 
    u1 = std::move(u2); // line 7 
    std::shared_ptr<int> s1(i); // line 8 
    std::shared_ptr<int> s2; 
    s2 = s1; 
} 

我编译G ++ 4.6和-std=c++0x,并得到一个段错误。

如果我将第7行更改为u2 = std::move(u1);(即错误),它会消失。 如果我将第8行更改为std::shared_ptr<int> s1(new int(3));(当然我不想),它也会消失。如果我从第8行删除也没有段错误。

所以没有伤害,但我不明白为什么应该有一个段错误。据我了解,
在第7行空指针分配给u1。没有重置(),没有范围的结束。尽管如此,i似乎从那里无效。这是否满足?这意味着移动指针时必须非常小心,因为另一个对象可能会被销毁!

您认为如何?我该如何保护自己?

谢谢,斯特芬

回答

11

您的第8行是错误的:一旦您在unique_ptr中捕获i,您不得再次将其分配给其他所有权对象!每个店主都会尝试删除*i,这是错误的。

相反,您应该创建一个从独特指针共享指针:

std::shared_ptr<int> s1(std::move(u2)); 

(此外,你必须u1u2以错误的方式。)

+1

困扰我的是,我可以用'-pedantic -Wall -Wextra'编译时甚至不会发出警告。答案真的只是“不要!”? – steffen

+2

@steffen:的确,答案是“不要”。没有保护'int * p = new int; do_crazy_stuff(P); be_insane(P); take_ownership(P);'。编译器无法真正知道你将如何处理指针。 –

+0

真的......感谢您的妄想:) – steffen

3

这条线:

u1 = std::move(u2); 

使由u1存储先前的指针被删除。因此,你的i指针被释放。持有free'd指针的创建shared_ptr是未定义的行为。

+0

耶。我想到了。看到我的评论Kerrek:没有任何警告。编译器让我们在这里伤害自己! – steffen

+0

无论哪种方式分配唯一指针都没有问题。默认构造的唯一指针为null,并且赋值会正确处理旧资源。行'u1 = std :: move(u2);'删除'* i',然后'u1'和'u2'都为空。 –

+0

@KerrekSB我从来没有说过分配unique_ptr有什么问题。 OP做这件事的方式是,在移动分配'u2'后,'u1'所保持的指针被释放。问题是他创建了一个shared_ptr到(已经free'd)指针。 Steffen,编译器无法知道shared/unique_ptr做了什么,他们存储的指针。 – mfontanini