多态 r 值引用?

Polymorphic r-value references?

如果我想在 class 中存储一个多态对象,我的第一个想法是如下所示:

struct Base {
    virtual void print() const {
        std::cout << "Base !";
    }
};

struct Derived: public Base {
    void print() const {
        std::cout << "Derived !";
    }
};

struct PolymorphicWrapper {
    std::unique_ptr<Base> base;
};

std::unique_ptr<Base> 的问题在于它会导致复杂的所有权问题和指针语义。虽然引用/原始指针可以具有多态行为,但它们不能绑定到右值。

但是我刚刚发现右值引用是多态的!!

例如:

Base && base = Derived();
base.print(); // Derived !

Base&& base2 = Base();
base2.print(); // Base !

我什至可以在 class!

中存储一个 r - 值引用
struct PolymorphicWrapper {
     Base&& base;
     PolymorphicWrapper(auto iBase) : base(std::move(iBase)) {} // auto to prevent object slicing
};

然而,这似乎好得令人难以置信。我在这里错过了什么吗?这是未定义行为的例子吗?

std::move 创建一个右值 reference 到一个现有的左值,它明确地将其标记为准备好从中移动。您可以从中初始化另一个右值引用,但是在特殊的生命周期延长情况下您 不是 有两个原因:

  • 它需要一个实际的右值(即刚刚在表达式中构造并且从未通过引用传递的对象);

  • 更重要的是,它根本不适用于引用成员。

Note: I'm reasonably sure that I've got this right, but I cannot seem to find a standard quote, probably because I'm getting lost in the aggregate initialization and temporary materialization wording. Language lawyers welcome.

因此,您只是存储了对构造函数参数的引用,该参数在所述构造函数的末尾消失并使引用悬空。

请注意,当将任意类型擦除对象存储为成员时,在一般情况下您无法避免动态分配,如果只是因为动态类型的大小未知且无界。 std::unique_ptr 是这种情况的首选,但如果您愿意,您也可以设计自己的带有小对象存储的类型擦除容器。