逐渐构建一个对象

int*_*lfx 21 c++

假设有两个类的层次结构(class Derived: public Base).这两个类都有很大的内存占用和昂贵的构造函数.请注意,这些类中没有任何内容在堆中分配:它们只是有一个大的sizeof.

然后有一个具有快速路径(始终执行)和慢速路径(有条件地执行)的功能.快速路径需要一个Base实例,慢速路径需要一个Derived从现有基础构建的实例.此外,只有在快速路径之后才能做出慢速路径决定.

当前代码如下所示:

void f()
{
    Base base;
    /* fast path */

    if (need_slow_path) {
        Derived derived (base);
        /* slow path */
    }
}
Run Code Online (Sandbox Code Playgroud)

这是低效的,因为需要将基数复制到派生中; 基数也被分配两次,存在堆栈溢出的风险.我想要的是:

  • Derived例如,分配内存
  • 打电话Base给它
  • 执行快速路径
  • 如果需要,Derived在现有Base实例上调用ctor 并执行慢速路径

在C++中有可能吗?如果没有,有哪些可行的解决方法?显然,我正在努力优化速度.

Rei*_*ica 32

我担心这不可能就像你写的那样 - 任何Derived 必须调用Base子对象的构造函数的构造函数,所以合法地执行它的唯一方法是首先调用Base析构函数,我相信你不希望这样.

但是,通过轻微的重新设计应该很容易解决这个问题 - 更喜欢组合而不是继承,并创建Derived一个单独的类来存储引用(在一般意义上;它当然可以是指针)Base并使用它.如果访问控制是一个问题,我觉得这friend是合理的.

  • @intelfx我担心这种变化对性能影响的唯一真实答案是:"对其进行分析并查看." (3认同)

Tan*_*til 11

您应该稍微改变您的设计,以将您对继承的依赖性改为对组合的依赖.

您可以将派生类的成员(不存在于基类中)封装到另一个类中,并在派生类中保留它的空引用.

现在直接初始化派生类而不初始化新类的对象.

每当需要慢速路径时,您都可以初始化并使用它.

优点

  • 派生类和基类之间的继承关系得以保留.
  • 永远不会复制基类对象.
  • 你有派生类的延迟初始化.

  • @intelfx:你试过吗?如果还没有,你怎么知道在应用编译器暗魔法之后会发生什么?我理解你对它的直觉,但是在优化方面,你应该衡量. (5认同)

Yak*_*ont 7

我可以假装它.

移动/衍生为所有的数据optional(它是booststd::ts::optional建议用于交C++ 14,或手轧).

如果你想慢速路径,初始化optional.否则,请保留为nullopt.

将有一个bool开销,并在您分配/比较/销毁隐式时进行检查.像virtual函数一样的东西derived(即你必须手动管理动态的dispath).

struct Base {
  char random_data[1000];
  // virtual ~Base() {} // maybe, if you intend to pass it around
};
struct Derived:Base {
  struct Derived_Data {
    std::string non_trivial[1000];
  };
  boost::optional< Derived_Data > m_;
};
Run Code Online (Sandbox Code Playgroud)

现在我们可以创建一个Derived,只有在我们构建m_.emplace()Derived_Dataget 之后.仍然存在的一切都在一个连续的内存块中(如果构造的话,booloptional轨道注入m_).