我有一个类Animal,它是少数不同动物的基类,以及一个类,它将shared_prt存储到向量中的动物。我不熟悉智能指针,但我必须在我的代码中使用它们来处理继承。它似乎工作正常,但在我的代码到达“Herd”的析构函数后,它会抛出一个error。 怎么了?
class Animal {
public:
Animal(string _sound) :
sound(_sound) {}
void give_sound() {
cout << sound << " ";
}
bool operator==(Animal arg) {
return (typeid(*this).name() == typeid(arg).name());
}
protected:
string sound;
};
class Dog : public Animal {
public:
Dog() : Animal("woof") {}
};
class Cat : public Animal {
public:
Cat() : Animal("meow") {}
};
class Cow : public Animal {
public:
Cow() : Animal("moo") {}
};
class Herd {
public:
Herd() {}
~Herd() {
vec.clear();
}
Herd operator+(Animal *arg) {
shared_ptr<Animal> ptr(arg);
vec.push_back(ptr);
return *this;
}
void operator+=(Animal *arg) {
shared_ptr<Animal> ptr(arg);
vec.push_back(ptr);
}
void make_noise() {
vector<shared_ptr<Animal>>::iterator v = vec.begin();
while (v != vec.end()) {
(*v)->give_sound();
v++;
}
cout << endl;
}
private:
vector<shared_ptr<Animal>> vec;
};
int main() {
Herd herd;
Dog d1, d2;
Cat c1, c2;
cout << "sound 1: " << endl;
herd.make_noise();
herd += &d1;
herd += &c1;
cout << "sound 2: " << endl;
herd.make_noise();
herd += &d2;
herd += &c2;
cout << "sound 3: " << endl;
herd.make_noise();
//herd = herd - &d1;
//herd = herd - &d2;
cout << "sound 4: " << endl;
herd.make_noise();
return 0;
}
编辑:没有vec.clear()它也会崩溃。
答案 0 :(得分:2)
Dog d1, d2;
Cat c1, c2;
这些对象具有自动存储持续时间。他们并不意味着拥有智能指针。
智能指针的用例是堆分配,例如:
herd += new Dog;
答案 1 :(得分:1)
您的问题是使用自动存储持续时间传递变量的地址。 请参阅:Stack, Static, and Heap in C++
这是您的代码中发生的事情:
您创建具有自动存储持续时间的变量:
Dog d1
它会在超出范围后自动销毁(在你的主要功能结束时)
然后,将它的地址传递给一个将该地址存储在SharedPtr中的函数:
Herd operator+(Animal *arg) {
shared_ptr<Animal> ptr(arg);
vec.push_back(ptr);
return *this;
}
这样做你告诉shared_ptr它负责删除这个对象。 (简单来说,共享指针的析构函数将调用delete Animal
)
结果你的对象将被释放两次,这是被禁止的。
您应该使用:
而不是使用原始指针operator+(shared_ptr<Animal> arg)
并按以下方式分配您的对象:
std::shared_ptr<Dog> d1 = std::make_shared<Dog>();
答案 2 :(得分:1)
它有什么问题?
在此代码中,您尝试使用堆栈分配的对象创建shared_ptr
。这导致双重删除此对象,第一个发生在堆栈对象超出范围时。第二个发生在shared_ptr
运算符中的delete
析构函数中。第二个无效,程序崩溃。
Herd operator+(Animal *arg) {
shared_ptr<Animal> ptr(arg);
vec.push_back(ptr);
return *this;
}
void operator+=(Animal *arg) {
shared_ptr<Animal> ptr(arg);
vec.push_back(ptr);
}
答案 3 :(得分:0)
我可以看到两个明显的问题。
正如其他人所提到的,第一个是shared_ptr
假设它管理的对象是动态创建的(使用运算符new
),因此使用运算符delete
释放它(除非自定义删除器)在构造代码不执行的shared_ptr
时提供。将operator delete应用于具有auto
存储持续时间的对象会导致未定义的行为。
第二个问题 - 在修复第一个问题后最终会遇到的问题 - 是类Animal
没有virtual
析构函数。即使使用运算符new
创建对象,运算符delete
也会导致从Animal
派生的实际类型的对象的未定义行为(即,如果实际对象的类型为Cat
,Dog
等。)