否则使用unique_ptr用于所有权和原始指针?

时间:2012-09-23 19:17:29

标签: c++ c++11 unique-ptr ownership

我是C ++ 11-some some code。我有

class X { /* */ };

class A {
    std::vector<X*> va_x;
};

class B {
    std::vector<X*> vb_x;
    std::vector<A> vb_a;
};

&#34; va_x&#34;的X * s在我的班级内部A指向也被&#34; vb_x&#34;的X * s指向的对象。我的班级里面。

现在我想使用智能指针。对我来说,似乎很清楚,B类拥有X *指向的对象的所有权(特别是因为我的A实例属于B)

所以我应该在B中使用unique_ptr for X:

class B {
    std::vector<unique_ptr<X>> vb_x;
    std::vector<A> vb_a;
};

我的问题是,我应该为A班做些什么?我应该保留原始指针吗?通过这样做,在我的单元测试中,我必须承认它导致尴尬的事情(imo),例如(不要担心封装,这不是重点):

unique_ptr<X> x(new X());
A a;
a.va_x.push_back(&(*x)); //awkward, but what else can I do?

A.vb_a.push_back(a); //ok
B.vb_x.push_back(move(x)); //ok

2 个答案:

答案 0 :(得分:10)

您可以使用x.get(),它将返回内部指针。

除此之外,是的,使用原始指针来处理非拥有引用是可行的方法,另请参阅this question

答案 1 :(得分:-1)

正如Xeo在他的回答中所说,解决方案通常是使用x.get()

FILE的示例,只要需要访问x.get(),就会使用void file_deleter(FILE *f) { fclose(f); } [...] { std::unique_ptr<FILE, decltype(&file_deleter)> f(fopen("/tmp/test.tmp", "rw"), &file_deleter); // read/write use f.get() as in: fread(buf, 1, sizeof(buf), f.get()); fwrite(buf, 1, sizeof(buf), f.get()); // fclose() gets called in the deleter, no need to do anything }

x.release()

但是,在您的情况下,您需要使用A a; { unique_ptr<X> x(new X()); a.va_x.push_back(&(*x)); // this is wrong } // here a[0] is a dangling pointer

&(*x)

a将获取原始指针并在unique_ptr<>向量中制作副本。但是,在}超出范围时,该指针将被删除。所以在a之后,release()向量中的指针不再好了(虽然它可能会工作一段时间。)

传输裸指针的正确方法是使用 a.va_x.push_back(x.release()); // this works 函数,如下所示:

a

在那一行之后,指针仅在push_back()向量中。它是从唯一指针释放出来的,并且调用者现在负责管理该资源。

重要提示: bad_alloc可能会抛出(bad_alloc),如果发生这种情况,资源就会丢失。为了避免这个问题(如果您的软件捕获 a.va_x.reserve(a.va_x.size() + 1); // malloc() happens here a.va_x.push_back(x.release()); // no `bad_alloc` possible here 并继续运行),您需要首先在向量中保留空间,如下所示:

bad_alloc

这样,unique_ptr将在该语句上发生,而资源仍然附加到shared_ptr,并且在异常的情况下不会泄漏它。

所有这些都说,你可能需要一个unique_ptr。这些可以毫无困难地复制。 shared_ptr更多地用于分配一次的资源,然后忘记一个函数返回或删除一个对象。当涉及(许多)副本时,class X { typedef std::shared_ptr<X> pointer_t; [...] } class A { std::vector<X::pointer_t> va_x; } X::pointer_t x(new X()); A a; a.va_x.push_back(x); // much cleaner and the pointer is still managed 更有意义。

$cats