shared ptr — ошибка сегментации с shared_ptr векторного элемента в переполнении стека

Я новичок в C ++, и мне очень трудно понять реляционные механизмы. Я пришел из PHP с базами данных и ORM, и мне не удалось воспроизвести очень простой случай. Сбой программы с ошибкой сегментации в строке «atomic.h» 49 { return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); }, Проблема возникает из shared_ptr, хотя я не очень понимаю, как использовать умные указатели (я прочитал сотни статей и ТАК вопросов о них, но все еще очень загадочно).

Не имея возможности сделать рабочий указатель на элемент репозитория, мои попытки установить отношения один-ко-многим и многие-к-одному между классами с треском провалились. Я должен что-то упустить, или, может быть, это не совсем так, как мы должны делать это в C ++?

Примечание: я компилирую с GCC6.3 с C ++ 17, используя только std, но не boost.

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
}

2

Решение

TLDN’R: Вы должны либо использовать вектор std :: shared_ptr в репозитории, либо изменить 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 дважды на одном и том же объекте, и это может привести к ряду странных действий, и вам повезло, что в вашем случае это ошибка сегментации.

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();
}
};

Если вы уверены, что Автомобиль будет уничтожен до уничтожения Хранилища:

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

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector