C++标准是否允许复制任意多态数据结构?
Does the C++ standard allow for copying an arbitrary polymorphic data structure?
我搜索了StackOverflow,但我找不到直接解决这个问题的问题。
首先是一些上下文:我正在尝试在C++中实现一个可以处理多态数据的Either
类型,就像你可以在没有new
-关键字的情况下抛出std::runtime_error
一样。对于基元类型、POD 和引用,一切都可以正常工作,但鉴于我们无法预先知道多态数据结构的大小,事情变得更加困难。然后,我想将结构复制到堆上的原始缓冲区,以便我可以像在堆栈上一样传递它。
Either<L, R>
类型示例:
Either<std::runtime_error, int> doSomeStuff() {
if (err) {
return left(std::runtime_error("Not right!"));
}
return right(42);
}
我尝试了像std::memcpy(buf, reinterpret_cast<char*>(static_cast<T*>(&value)), sizeof(T))
这样的东西,但我不断收到SIGSEGV错误。这是因为,正如我所怀疑的那样,多态结构保留了额外的簿记,在复制时会损坏吗?有没有办法在堆上保存任意多态结构T
,以便我可以像普通堆栈分配的对象一样传递它?还是在今天的C++标准中这样的事情"未定义"?
更新:这是我到目前为止的代码。它并不漂亮,但它是我得到的最好的。
struct ConstBoxRefTag { };
struct BoxMoveTag { };
struct PlainValueTag { };
// struct BoxValueTag { };
template<typename T>
struct GetTag { using type = PlainValueTag; };
template<typename T>
struct GetTag<const Box<T>&> { using type = ConstBoxRefTag; };
template<typename T>
struct GetTag<Box<T>&&> { using type = BoxMoveTag; };
template<typename T>
struct GetTag<Box<T>> { using type = ConstBoxRefTag; };
template<typename T>
class Box<T, typename std::enable_if<std::is_polymorphic<T>::value>::type> {
void* buf;
size_t sz;
template<typename R, typename Enabler>
friend class Box;
public:
using Type = T;
template<typename R>
Box(R val): Box(typename box::GetTag<R>::type {}, val) {}
template<typename R>
Box(ConstBoxRefTag, R oth): buf(std::malloc(oth.sz)), sz(oth.sz) {
std::memcpy(buf, oth.buf, oth.sz);
}
template<typename R>
Box(BoxMoveTag, R oth): buf(std::move(oth.buf)), sz(std::move(oth.sz)) {
oth.buf = nullptr;
};
template<typename R>
Box(PlainValueTag, R val): buf(std::malloc(sizeof(R))), sz(sizeof(R)) {
std::memcpy(buf, reinterpret_cast<void*>(static_cast<T*>(&val)), sizeof(R));
}
template<typename R>
R as() const {
static_assert(std::is_base_of<T, R>::value, "Class is not a subtype of base class");
return *static_cast<const R*>(reinterpret_cast<const T*>(&buf));
}
T& reference() {
return *reinterpret_cast<T*>(&buf);
}
const T& reference() const {
return *static_cast<T*>(&buf);
}
~Box() {
if (buf != nullptr) {
reference().~T();
std::free(buf);
}
}
};
事实上,该标准最近增加了一个"平凡可复制"的概念,这样在不能平凡可复制的对象上使用memcpy
不会产生有效的对象。 在引入"平凡可复制"之前,这是由 POD 控制的。
若要创建 C++ 对象的副本,需要调用其复制构造函数。 没有标准的多态方法可以做到这一点,但某些类层次结构选择包含虚拟clone()
函数(或类似函数),以满足您的需求。
您的另一种选择是找到完全避免复制的方法。
相关文章:
- 多态性和功能结合
- 具有默认模板参数的多态类的模板推导失败
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 多态二进制函数
- 访问存储在向量C++中的结构的多态成员
- 使用取消引用的指针的多态性会产生意外的结果.为什么?
- 将 std::allocate_shared 与多态资源分配器一起使用
- 通过switch和static_cast访问多态对象的运行时类型
- C++boost序列化多态性问题
- 多态杆件变量 - 类设计
- 如何查找哪个类对象位于数组的特定索引上(多态性)
- 如何在多线程中正确使用unique_ptr进行多态性?
- Doees the 'this' 指针参与虚函数的多态行为
- C++ 在堆栈中包含多态属性的类对象存储
- 基类和派生类的多态赋值运算符
- 转身多态对象
- 如何在基类指针向量的元素上应用重载的多态函数
- 具有智能指针的多态性
- C++标准是否允许复制任意多态数据结构?
- 我可以知道一个多态对象是否实现了一个任意的抽象类