多态就地重建c++和/或克隆模式

polymorphic in place re-construction in C++ and/or clone pattern

本文关键字:模式 重建 c++ 多态      更新时间:2023-10-16

我正在尝试做以下技巧:

class A {
    virtual ~A();
    virtual void reset() {
        this->~A();
        construct(); // this should magically use placement-new of the derived type on 'this', so that if called from an A pointer to a B class, it works.
    }
 };
 class B : public A {
     ...
 };

如何以最通用的方式实现construct ?

我想使用现有的默认构造函数,这是我对现有层次结构添加的更改。我目前正在考虑两个选择:

1) construct()在每个派生类中实现,是对放置new的调用。

2)将所有构造函数移动到每个类的init()函数中。这与我们的工作方式是反直觉的,而且还可能导致只能用初始化器列表初始化的东西混乱。

"你将如何以最通用的方式实现construct ?"

struct AA {
    virtual void reset() = 0;
    virtual ~AA() {}
};
template<class Derived>
class A : public virtual AA {
              // ^^^^^^^ prevent nasty problems introduced with eventually 
              //         multiple occurrence of AA in the inheritance hierarchy
public:
    virtual ~A();
    // No construct() necessary
    virtual void reset() {
        // Have an appropriate default constructor and assignment operator,
        // the latter is the equivalent for cloning
        static_cast<Derived&>(*this) = Derived();
    }
 };
 class B : public A<B> {
     // ...
 };
使用

 B b;
 AA* vp = &b;
 vp->reset();

还有两点:

  1. 永远不要显式地调用析构函数:this->~A();,这会带来麻烦
  2. 小心放置new(),它不仅不会为你的情况工作,它很少做人们通常想要的。

我的两分话,(尽管pi的答案更直接地回答了你的问题)一个类应该做一件事,而且只做一件事。一般来说,应该将内存管理和类实现分开。而你要做的就是压缩一个电话

获得相同功能的最直接方法是使用一个唯一的指针(c++ 11)。

std::unique_ptr<A> a(new B());
a.reset(new B());//deletes the old B and makes a new B.

如果您可以不使用非连续内存分配,那么这是可以的(并且提示,您几乎总是可以)。但让我们假设你不能(因为这违背了你的宗教信仰或其他什么)。好吧,这几乎就是你上面要做的。

 B a;//old reference
 a = B();//Reset!

它的行为完全像你写的"就地"重置调用,没有任何讨厌的副作用。

所有这些方法都有一个共同的缺陷。您必须放弃旧引用的资源来承担新引用的资源。没有重用,这是一个遗憾。解决这个问题的唯一方法是提供手动"重置"功能。STL中的类通过"assign"函数来实现这一点,并且通常支持的不仅仅是默认构造函数。

 std::vector<int> x(100);//made a vector x of 100
 x.assign(50);//acts like x=std::vector<int>(50), but will most likely reuse the memory

这就是PI在他的CRTP响应中得到的:它所做的是静态继承,即它强制一个重置函数而没有多态性的惩罚。