C ++ Зачем использовать объект в векторных сегментах? - PullRequest
1 голос
/ 27 марта 2019

Я хочу создать вектор объектов "Act", которые содержат указатели на динамически размещаемые объекты "Eat" или "Drink".Новые объекты размещаются следующим образом:

action_vector.emplace_back(Act::BehaviorType::eat);

Однако, это происходит с ошибками, и я не могу понять, почему.Я думал, что emplace_back будет неявно вызывать конструктор перемещения, а не деструктор, но по какой-то причине это так (как мне кажется), что все портит.

Есть ли способ успешно создать вектортакие объекты?

Вот остаток кода вместе с его выводом.Извините, если это немного многословно, но в основном это просто шаблон стратегии.

#include <iostream>
#include <vector>

class IBehavior
{
public:
    IBehavior() = default;
    virtual ~IBehavior() = default;
    virtual void execute() = 0;
};

class Drink : public IBehavior
{
public:
    Drink(): IBehavior() {}
    ~Drink() {}
    void execute() { std::cout << "Drinking" << std::endl; }
};

class Eat : public IBehavior
{
public:
    Eat(): IBehavior() {}
    ~Eat() {}
    void execute() { std::cout << "Eating" << std::endl; }
};


class Act
{
    IBehavior * b;

public:

    enum class BehaviorType { eat = 0, drink = 1 };

    Act() = default;
    ~Act()
    {
        std::cout << "Calling the destructor" << std::endl;
        delete b;
    }
    Act(BehaviorType b_type) { SetBehavior(b_type); }

    Act(Act&& act)
    {
        std::cout << "Calling the move constructor" << std::endl;
        this->b = act.b;
    }


    void SetBehavior(BehaviorType b_type)
    {
        if(b_type == BehaviorType::eat) b = new Eat();
        if(b_type == BehaviorType::drink) b = new Drink();
    }

    void execute() { b->execute(); }
};


int main(int argc, char * argv[])
{
    std::vector<Act> action_vector;

    for(int i = 0; i < 10; ++i)
    {
        action_vector.emplace_back(Act::BehaviorType::eat);
        action_vector[i].execute();
    }

    return 0;
}

output:

Eating
Calling the move constructor
Calling the destructor
Eating
Calling the move constructor
Calling the move constructor
Calling the destructor
Calling the destructor
Segmentation fault: 11

1 Ответ

4 голосов
/ 27 марта 2019

Ваш конструктор перемещения копирует b, а деструктор удаляет b, поэтому, если вы переместите конструктор экземпляра, то одно и то же значение указателя будет удалено дважды, что имеет неопределенное поведение.

Общее решение: используйте умный указатель.


Еще одна ошибка: конструктор по умолчанию оставляет b неинициализированным. Когда созданный по умолчанию объект уничтожается, неинициализированный указатель удаляется и поведение не определено. Умный указатель исправляет это также.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...