C++ 中矢量元素 shared_ptr 的分段错误
Segmentation fault with shared_ptr of a vector element in C++
我是 C++ 的新手,我很难理解关系机制。我来自 PHP 数据库和 ORM 背景,但我无法重现一个非常简单的案例。该程序因 "atomic.h" 第 49 行 { return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); }
中的分段错误而崩溃。问题来自shared_ptr,虽然我不太明白如何使用智能指针(我已经阅读了数百篇文章和关于它们的SO问题,但仍然很神秘)。
由于无法在存储库元素上创建工作指针,我在 类 之间建立一对多和多对一关系的尝试都惨遭失败。我一定是遗漏了什么,或者这根本不是我们在 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
}
TLDN'R:您应该在存储库中使用 std::shared_ptr 的向量,或者将 getNewCar
更改为 return 参考。
我稍微更改了您的代码以使输出更详细:
#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
认为是第一个跟踪对象的智能指针。所以当它被销毁时(或者它的最后一个副本,如果你做了一些)这个对象的析构函数将被调用。
因此,如果您认为 Car 的寿命比它来自的存储库更长:
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 会在 Repository 被销毁之前被销毁:
class Repository
{
std::vector<Car> collection;
public:
Car& getNewCar()
{
Car newCar;
collection.push_back(newCar);
return collection.back();
}
};
我是 C++ 的新手,我很难理解关系机制。我来自 PHP 数据库和 ORM 背景,但我无法重现一个非常简单的案例。该程序因 "atomic.h" 第 49 行 { return __atomic_fetch_add(__mem, __val, __ATOMIC_ACQ_REL); }
中的分段错误而崩溃。问题来自shared_ptr,虽然我不太明白如何使用智能指针(我已经阅读了数百篇文章和关于它们的SO问题,但仍然很神秘)。
由于无法在存储库元素上创建工作指针,我在 类 之间建立一对多和多对一关系的尝试都惨遭失败。我一定是遗漏了什么,或者这根本不是我们在 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
}
TLDN'R:您应该在存储库中使用 std::shared_ptr 的向量,或者将 getNewCar
更改为 return 参考。
我稍微更改了您的代码以使输出更详细:
#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
认为是第一个跟踪对象的智能指针。所以当它被销毁时(或者它的最后一个副本,如果你做了一些)这个对象的析构函数将被调用。
因此,如果您认为 Car 的寿命比它来自的存储库更长:
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 会在 Repository 被销毁之前被销毁:
class Repository
{
std::vector<Car> collection;
public:
Car& getNewCar()
{
Car newCar;
collection.push_back(newCar);
return collection.back();
}
};