8

我正在使用 C++11 编写一些代码。我有

class X { /* */ };

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

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

我的类 A 中的“va_x”的 X*s 指向的对象也被我的类 B 中的“vb_x”的 X*s 所指向。

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

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

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
4

2 回答 2

10

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

除此之外,是的,使用原始指针来处理非拥有引用是要走的路,另请参阅这个问题

于 2012-09-23T19:35:05.593 回答
-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代替。这些可以毫无困难地复制。Aunique_ptr更多的是用于分配一次资源,然后忘记一个函数返回或删除一个对象。当涉及(许多)副本时, ashared_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
于 2018-06-08T01:05:07.340 回答