繁体   English   中英

如何将 shared_ptr 变量 push_back 到 C++ 中的 shared_ptr 向量?

[英]How do you push_back a shared_ptr variable to a vector of shared_ptrs in C++?

我是 C++ 的初学者,具有 Python、Java 和 JS 的背景,所以在指针方面我仍在学习中。

我有一个共享指针向量。 在另一个 function 中,我将一个共享指针分配给一个变量并将其添加到向量中。 如果我在 function 退出后尝试访问添加的元素,则会发生分段错误:

class Bar
{
private:
    std::vector<std::shared_ptr<Foo>> fooVector;
}

void Bar::addToFoo()
{
    std::shared_ptr<Foo> foo (new Foo(…));
    fooVector.push_back(foo);
}
void Bar::otherMethod()
{
    // this method gets called sometime after addToFoo gets called
    …
    fooVector[anIndex]->baz(); // segfaults
    …
}

但是,如果 push_back 是一个共享指针而不是一个变量,它就可以工作。

// this works:
fooVector.push_back(std::shared_ptr<Foo>(new Foo(…)));

// this segfaults:
std::shared_ptr<Foo> foo (new Foo(…));
fooVector.push_back(foo);

我相信这是因为foo变量在addToFoo function 退出时被删除(如果我错了请纠正我)。 如何将shared_ptr变量push_back到 C++ 中的shared_ptrs vector


为什么使用变量

虽然直接将shared_ptr推入向量而不使用变量是可行的,但我更喜欢使用变量来做到这一点:

std::shared_ptr<Rider> rider;
switch (iProcessorModesParam)
{
    case PEAKS_MODE:
        rider = std::shared_ptr<Rider>(new PeaksRider(…));
        break;
    case RMS_MODE:
        rider = std::shared_ptr<Rider>(new RMSrider(…));
        break;
}
volumeRiders.push_back(rider);

PeaksRider 和 RMSrider 是 Rider 的子类。 我想将 Rider 的所有子类型存储在相同的 Riders 向量中。 我了解到,将 Rider 的子类型添加到 Riders 的向量中是行不通的,需要指针才能实现这种多态性:

std::vector<Rider> // doesn’t work with subtypes

std::vector<*Rider>
std::vector<std::shared_ptr<Rider>>

拥有std::shared_ptr<Rider> rider; 变量避免为每种类型的 Rider 重复.push_back(…)代码。

不是分配共享指针,而是用户reset方法。

rider.reset(new PeaksRider(…));

除此之外,您的代码片段对我来说似乎没问题。

段错误可能是由于索引变量(可能超出范围)引起的。 我建议您使用.at(index)从 vector 访问指针并将该部分代码包装在try..catch块中,看看真正的错误是什么。

而关于...

我相信这是因为 foo 变量在 addToFoo function 退出时被删除(如果我错了请纠正我)。

这不是真的,share_ptrs 使用本地计数器来获取 #of 引用。 一旦您将指针推向向量,计数器就会增加到 2,并且在控制退出 function 之后,计数器就会减少到 1。因此,您的 object 尚未被销毁。

创建共享指针实例,将其存储在变量中,然后对向量执行 push_back 没有问题。 只要您在调用“otherMethod”时使用的索引有效,您的代码就应该没问题。 但是,我对您的代码有一些建议:

  • 当您创建一个 shared_ptr 时,强烈建议通过“std::make_shared”来创建,以确保您的代码在所有情况下的安全性和正确性。 在另一篇文章中,您会找到一个很好的解释: Difference in make_shared and normal shared_ptr in C++
  • 当使用可能包含会导致越界访问(通常会导致分段错误)的值的变量访问向量的位置时,最好在使用向量之前放置断言,这样你就会检测到这些不需要的情况。

我刚刚写了一个小片段,您可以测试它来说明我刚才提到的内容:

#include <iostream>
#include <vector>
#include <memory>
#include <cassert>

class Foo
{
public:
    int data = 0;
};

class Bar
{
public:
    void addNewFoo(int d)
    {
        std::shared_ptr<Foo> foo(new Foo());
        foo->data = d;
        fooVector.push_back(foo);
    }

    void addNewFooImproved(int d)
    {
        auto foo = std::make_shared<Foo>();
        foo->data = d;
        fooVector.push_back(foo);
    }

    void printFoo(int idx)
    {
        assert(idx < fooVector.size());
        std::cout << fooVector[idx]->data << std::endl;
    }

private:
    std::vector<std::shared_ptr<Foo>> fooVector;
};

int main()
{
    Bar b;
    b.addNewFoo(10);
    b.addNewFoo(12);
    b.addNewFooImproved(22);
    b.printFoo(1);
    b.printFoo(2);
    b.printFoo(0);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM