使用C ++中的向量元素的shared_ptr进行分段错误

时间:2017-11-10 06:10:04

标签: c++ shared-ptr

我是C ++的新手,我很难理解关系机制。我来自PHP背景,包含数据库和ORM,但我无法重现一个非常简单的案例。程序在“atomic.h”第49行{ return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); }中因分段错误而崩溃。问题来自shared_ptr,虽然我真的不明白如何使用智能指针(我已经阅读了数百篇关于它们的文章和SO问题,但仍然非常神秘)。

如果无法在存储库元素上创建工作指针,我尝试在类之间建立一对多和多对一的关系都会失败。我一定是在遗漏某些东西,或者也许我们不应该在C ++中这样做?

注意:我只使用std编译GCC6.3和C ++ 17,而不是使用。

class Car : public enable_shared_from_this<Car> {
    //...
}

template <class Type>
class Repository<Type> {
    vector<Type> collection;
public:
    shared_ptr<Type> getNew() {
       Type newType;
       collection.push_back(newType);
       return shared_ptr<Type>(&collection.back());
       // I also tried this but program fails at this line although it compiles fine.
       // return collection.back().shared_from_this();
    }
}

class MainApp {
    Repository<Cars> cars;
    shared_ptr<Car> myCar;

public:
    MainApp() {
        myCar = cars.getNew();
    }
}

int main() {
    MainApp app; // OK - myCar points to the last car in cars repository
    return 0; // SIGEGV Segmentation fault
}

1 个答案:

答案 0 :(得分:3)

TLDN'R:您应该在存储库中使用std :: shared_ptr的vector或更改getNewCar以返回引用。

我更改了一些代码以使输出更加详细:

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

class Car
{
public:
    Car()
    {
        std::cout << "Car ctor @" << this << std::endl;
    }

    Car(const Car& car)
    {
        std::cout << "Car copy ctor @" << this << " from " << &car << std::endl;
    }

    Car& operator=(const Car& car)
    {
        std::cout << "Car assign operator @" << this << std::endl;
    }

    ~Car()
    {
        std::cout << "Car dtor @" << this << std::endl;
    }
};

class Repository
{
    std::vector<Car> collection;
public:
    std::shared_ptr<Car> getNewCar()
    {
        Car newType;
        collection.push_back(newType);
        return std::shared_ptr<Car>(&collection.back());
    }
};

int main()
{
    Repository rep;
    std::shared_ptr<Car> myCar = rep.getNewCar();
    return 0;
}

代码结果为:

Car ctor @0x7ffe35557217
Car copy ctor @0x25b6030 from 0x7ffe35557217
Car dtor @0x7ffe35557217
Car dtor @0x25b6030
Car dtor @0x25b6030

您遇到的问题是您的代码在同一个对象上执行两次Car析构函数,这可能导致许多奇怪的行为,您很幸运,在您的情况下,它是一个Segmentation错误。

您在存储库中使用的std::vector负责在销毁时删除其所有对象。指向某个对象的最后一个'std :: shared_ptr'也负责这样做。

排队:

return shared_ptr<Type>(&collection.back());

您获取当前属于std::vector的对象的地址,并使用指针创建std::shared_ptr。这个std::shared_ptr认为它是第一个跟踪对象的智能指针。因此,当它被销毁时(或者如果你做了一些它的最后一个副本),将调用这个对象的析构函数。

因此,如果您认为汽车的寿命将超过其所在的存储库:

class Repository
{
    std::vector<std::shared_ptr<Car>> collection;
public:
    std::shared_ptr<Car> getNewCar()
    {
        collection.push_back(std::shared_ptr<Car>(new Car()));
        return collection.back();
    }
};

如果您确定在销毁存储库之前销毁Car:

class Repository
{
    std::vector<Car> collection;
public:
    Car& getNewCar()
    {
        Car newCar;
        collection.push_back(newCar);
        return collection.back();
    }
};