std::move 具有指向派生 class 实例的基 class 的唯一指针

std::move with a unique pointer of a base class pointing to an instance of a derived class

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

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

我接下来的问题是:

这是我的代码。请注意,我只包含了命令 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 实现了上述接口:

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)));
}

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

但是你确实有内存泄漏,你分配的 ccc 对象没有被任何人 deleted,你正在从它构建一个新对象,但泄漏了原始对象本身. 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;

您不能 "move" 原始指针 - 无论如何都没有意义。您可以有意义地移动 unique_ptr,但这不会将对象移动到任何地方,它仅意味着该 pointed-to 对象(作为分配的内存)的所有权移动到其他 someplace/someone。

不过那不是你在做的;您的代码将您的临时对象移动到 newly-allocated 对象中(这会导致内存泄漏,如@Preatorian )。

What would be a better way of handling moving around objects regardless of their type ?

使用指针 实际上处理对象 "moves" 的合理方式,无论它们的类型如何:您根本不会(或很少)实际移动任何对象,您只使用指向它们的指针。如果您想要 type-obliviousness,您可能无法使用类型化的 unique_ptr,但您可以使用带有自定义删除器的 void *unique_ptr<void> 指针。

另一种选择是使用 std::any's,没有指针。如果对象很小,移动它们很便宜,如果它们很大,它们会在里面隐藏指针,所以移动它们又很便宜。从某种意义上说,这种替代方案更安全,而不是违反分段和重新解释垃圾,如果您尝试错误的类型,您只会得到异常。