微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我可以在固定大小的假设下拥有一个多态值向量吗?

如何解决我可以在固定大小的假设下拥有一个多态值向量吗?

考虑下面的代码,派生类用函数的变体替换了虚成员函数,但没有添加任何新的成员变量。 Base 和 Derived 的值被添加一个公共容器 std::vector 中,正如预期的那样,Derived 值被切片。然而,通过将 Derived 值在内存中的表示复制到容器中,该值实际上只是部分切片。

#include <iostream>
#include <vector>

class Base {
public:
    Base() = default;
    Base(float arg) : a{ arg } {};

    virtual float doSomething(float b) const { return a + b; }

    float a;
};

class Derived : public Base {
public:
    Derived() = default;
    Derived(float a) : Base{ a } {};

    float doSomething(float b) const { return a - b; }
};

int main()
{
    Base b{ 1.0f };
    Derived d{ 1.0f };

    std::cout << sizeof(b) << "," << sizeof(d) << '\n';  // 8,8

    std::vector<Base> v{ b,d };  // d is sliced
    std::cout << v[0].doSomething(2.0f) << '\n';  // 3
    std::cout << v[1].doSomething(2.0f) << '\n';  // 3 as d was sliced

    memcpy(&v[1],&d,sizeof(d));  // copy the representation of d over to v[1]
    std::cout << v[1].doSomething(2.0f) << '\n';  // Now -1
}

由于指向虚函数表的指针,值的大小为 8,这是实现上述多态性的方法。 v[1] 的类型总是 Base,所以如果 Derived 添加一个新的成员函数,就不可能调用它。实际上 v[1] 仍然被切分到 Base,但重新实现了 Derived 的成员函数

假设 Base 本质上是 POD,但添加了虚拟成员函数,所有这些都是 const,即内存可复制,并且 Derived 仅重新实现这些成员函数

  1. 上述代码是否属于未定义行为?
  2. 如果是这样,有没有办法在没有 memcpy 或等效项的情况下以定义行为的方式实现这一点?
  3. 如果这是一个常见的模式,它叫什么名字?

解决方法

阿米尔的回答正是我需要的。但是,为了完整起见,我现在将填写我提出问题时真正想要的内容。

可以在 std::vector 中存储不同类型的值,只要这些类型本身适当地包装在一个公共类型中,本质上是一种类型擦除。容器内部将有一个固定长度的缓冲区并具有适当的对齐方式,例如使用 std::aligned_storage。然后,您将使用新的布局和带有克隆函数的每种类型的模板来实现复制/移动语义。

一个明显的增强是允许类型过大,使得 unique_ptr 无法容纳缓冲区。从这个角度来看,容器实际上是一个围绕 unique_ptr 的包装器,其中包含了一个小的缓冲区优化。

我计划将其作为自己的练习来实施,如果/有机会,我会编辑此答案。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?