std :: move,其基类的唯一指针指向派生类

时间:2018-04-02 18:32:28

标签: c++ c++11 design-patterns smart-pointers unique-ptr

我正在尝试在C ++中实现命令和策略设计模式。

我有一个命令界面和一个策略界面(为每个玩家分配不同的策略,因此玩家可以是手动,AI攻击性,AI防守,AI随机等等)。策略具有一系列函数,这些函数返回ICommand类型的唯一指针(例如命令接口),该指针指向派生命令类的实例。我的想法是以特定的方式在我的策略中创建一些命令,然后将指向特定命令的唯一指针返回给执行命令的游戏(命令调用者),而不管该命令是什么。

我的以下问题是:

  • 如果我移动一个由基类的唯一指针指向的派生类的实例,我会得到对象切片吗?

  • 如果是这样,那么处理物体移动的更好方法是什么?

这是我的代码。请注意,我只包含命令choose_combo的代码,因为其余部分有点多余:

我有一个标准命令的接口:

class Igame_command {
protected: // protected, since Igame_command is an interface.
    player &p;
    game_model &gm;

    Igame_command(player p, game_model gm) : p(p), gm(gm) {}

public:
    virtual void execute() = 0;
};

然后我有一些实现上述接口的派生类:

class choose_combo_c : private Igame_command {
    combo c;
    int vp;
public:
    void set_combo(combo c) { this->c = c; }
    void set_vp(int vp) { this->vp = vp; }
    combo get_combo() { return c; }
    int get_vp() { return vp; }
    choose_combo_c::choose_combo_c(player &p, game_model &gm);

    void execute() override;
};

然后我为我的策略设置了一个界面:

class Istrategy {
protected:
application &app;
game_model &gm;
player &p;

Istrategy(application &app, game_model &gm, player &p) : app(app), gm(gm), p(p) {}

public:

virtual std::unique_ptr<Igame_command> choose_combo(
        std::vector<combo> &available_combos, std::vector<int> &available_combos_vp) = 0;

};

例如,对于手动策略,选择组合:

std::unique_ptr<Igame_command> manual_strategy::choose_combo(
        std::vector<combo> &available_combos, std::vector<int> &available_combos_vp) override {

    // code to have the player make a choice, it sets the int choice...    

    choose_combo_c* ccc = new choose_combo_c(p, gm);
    ccc->set_combo(available_combos.at(choice));
    ccc->set_vp(available_combos_vp.at(choice));
    return std::unique_ptr<Igame_command> (new choose_combo_c(std::move(*ccc)));
}

2 个答案:

答案 0 :(得分:0)

unique_ptr<T>存储T*,而不是T,因此您不会在示例中获得任何对象切片。

但是你确实有内存泄漏,你分配的ccc对象不是delete d任何人,你移动构建一个新对象,但泄漏原始本身。 manual_strategy::choose_combo中的代码应写为

auto ccc = std::make_unique<choose_combo_c>(p, gm);  // create a unique_ptr<choose_combo_c>
// do stuff with it
ccc->set_combo(available_combos.at(choice));
ccc->set_vp(available_combos_vp.at(choice));

// simply return it here, a unique_ptr<Igame_command>
// will be constructed from the unique_ptr<choose_combo_c>
return ccc;

答案 1 :(得分:0)

无论如何,你无法“移动”原始指针 - 无意义。您可以有意义地移动unique_ptr,但这不会将对象移动到任何地方,它只意味着该指向对象的所有权(作为已分配的内存)移动到某个地方/其他人。

但是,这不是你正在做的事情;你的代码将你的临时对象移动到一个新分配的对象(导致内存泄漏,如@Preatorian points out)。

  

处理物体的更好方法是什么?无论其类型如何?

使用指针 实际上是对象“移动”的合理方式,无论其类型如何:您根本不会(或很少)实际移动任何对象,您只需使用指向它们的指针。如果您想要键入遗忘,则可能无法使用键入的unique_ptr,但您可以将void *unique_ptr<void>指针与自定义删除符一起使用。

另一种选择是使用std::any,而不使用指针。如果物体很小,移动它们很便宜,如果它们很大,它们就会隐藏指针,所以移动它们又便宜了。从某种意义上来说,这种替代方案更安全,而不是分段违规和重新解释垃圾,如果你尝试错误的类型,你只会得到例外。