首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >带有shared_ptr向量的类析构函数会导致错误

带有shared_ptr向量的类析构函数会导致错误
EN

Stack Overflow用户
提问于 2016-11-16 10:30:28
回答 4查看 1.5K关注 0票数 0

我有一个类动物,它是几个不同动物的基类,一个类畜群,它将shared_prt存储在一个向量中给动物。我不熟悉智能指针,但我必须在有序的代码中使用它们来处理继承。它似乎工作得很好,但是在我的代码到达"Herd“的析构函数之后,它会抛出一个错误。它有什么问题?

代码语言:javascript
复制
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(),它也会崩溃。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-11-16 10:40:55

代码语言:javascript
复制
Dog d1, d2;
Cat c1, c2;

这些对象具有自动存储持续时间。他们不应该被管理,拥有聪明的指针。

智能指针的用例是堆分配,例如:

代码语言:javascript
复制
herd += new Dog;
票数 2
EN

Stack Overflow用户

发布于 2016-11-16 10:48:24

您的问题是传递具有自动存储时间的变量的地址。请参阅:C++中的堆栈、静态和堆

这就是您的代码中发生的情况:

创建一个具有自动存储持续时间的变量:

代码语言:javascript
复制
Dog d1

它将在超出作用域后自动销毁(在您的情况下,主要功能结束)。

然后,将它的地址传递给将此地址存储在SharedPtr中的函数:

代码语言:javascript
复制
Herd operator+(Animal *arg) {
    shared_ptr<Animal> ptr(arg);
    vec.push_back(ptr);
    return *this;
}

这样做,您可以告诉shared_ptr,它负责此对象的删除。(简单地说,共享指针的析构函数将调用delete Animal)

因此,您的对象将被释放两次,这是禁止的。

与其使用原始指针,不如使用:

代码语言:javascript
复制
operator+(shared_ptr<Animal> arg)

并以下列方式分配对象:

代码语言:javascript
复制
std::shared_ptr<Dog> d1 = std::make_shared<Dog>();
票数 2
EN

Stack Overflow用户

发布于 2016-11-16 10:51:43

它有什么问题?

在这段代码中,您尝试使用堆栈分配的对象创建shared_ptr。这将导致该对象的双重删除,第一次是在堆栈对象超出作用域时发生的。第二种是发生在shared_ptr析构函数中的delete算子。第二种是无效的,程序崩溃。

代码语言:javascript
复制
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);
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/40629783

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档