【问题标题】:Is there a performance/memory usage impact in non-polymorphic inheritance?非多态继承对性能/内存使用有影响吗?
【发布时间】:2016-10-22 20:35:31
【问题描述】:

我很好奇非多态类中继承的影响。具体来说,我正在编写两个智能指针类,都没有虚拟方法,并且都用于非常独特的目的。由于基本的运算符重载和一些标准函数是相同的,并且它们只需要一个成员变量,我想我可以使用基类来重用代码。这是我的意思的一个简单的模型

基类:

template <class T>
class Pointer_Impl
{
public:
    T & operator*() { return this->*m_pointer; }
    // etc.
protected:
    T *m_pointer;
    //protected to prevent instantiation without using = delete
    Pointer_Impl() {}
    Pointer_Impl(T *) {}
    //other constructors, assignment and move operators, destructor here
};

然后:

template <class T>
class PointerA : public Pointer_Impl<T>
{
public:
    PointerA() { m_pointer = nullptr; }
    PointerA(T * obj) { m_pointer = obj; }
    // other constructors, assignment and move operators, destructor, and any other class-specific functions here
};

问题:从缺少任何虚方法的基类派生是否存在内存或性能开销?因为它是一个智能指针实现,所以我想要的是精益求精。

我的直觉说不,不用担心,但我想从更聪明的头脑中确定。

【问题讨论】:

  • 因为它是一个智能指针实现,所以我正在寻找精简和平均。原始指针可能比智能指针更精简。他们当然更卑鄙......
  • @erip 当然,原始指针总是会更快,但我希望以尽可能低的开销尽可能快。否则,智能指针的意义何在?
  • 有几个拼写错误,缺少分号,错误的变量名,而且,如果构造函数是私有的,PointerA 无法创建基础子对象实例。
  • @user2079303 这是一个“简单的模型”来说明问题。我会检查错别字。
  • @JonHarper 我正在考虑查看程序集:) 无论如何,您不能像那样初始化父级的成员。您必须改为调用父构造函数。

标签: c++ c++11 inheritance smart-pointers


【解决方案1】:

没有任何形式的运行时性能损失(如果优化。显然调试版本可能会存储一些有关继承的数据)。

作为证据,观察以下程序的输出

程序1:

template <class T>
class PointerA
{
public:
    PointerA(T * obj) : m_pointer(obj) {}
    T & operator*() { return *this->m_pointer; }
    T *m_pointer;
};

程序2:

template <class T>
class Pointer_Impl
{
public:
    T & operator*() { return *this->m_pointer; }
protected:
    T *m_pointer;
    Pointer_Impl(T *) {}
};

template <class T>
class PointerA : public Pointer_Impl<T>
{
public:
    PointerA(T * obj) : Pointer_Impl<T>(obj) {}
};

常见的主要:

int main() {
    PointerA<int> p(new int);
    volatile int i = 42;
    *p = i;
    i = *p;
}

两者都产生相同的程序集:

main:
        subq    $24, %rsp
        movl    $4, %edi
        call    operator new(unsigned long)
        movl    $42, 12(%rsp)
        movl    12(%rsp), %eax
        movl    %eax, 12(%rsp)
        movl    $0, %eax
        addq    $24, %rsp
        ret

【讨论】:

  • 你们太棒了。我没想到会有实际的装配比较。
【解决方案2】:

性能影响

没有。如果没有virtual(虚拟继承或虚拟函数),您不会因使用基类而招致任何运行时惩罚。名称解析完全在编译时使用静态类型执行。

内存影响

没有。在没有virtual 的情况下,继承的类与直接具有相同字段作为成员的类之间没有有意义的区别。如果您有多个基类或virtual(继承或函数),这一切都会改变。

编译影响

编译时间可能会有一些影响;编译器将不得不跟踪更多的名称和模板实例。这有时是大型、大量模板代码库的问题。

【讨论】:

  • 美丽。如果没有人提出问题,这正是我所需要的。
【解决方案3】:

您的子类的构造函数表明该子类至少包含一个其他成员 m_object,但您没有显示。

在没有任何虚拟方法的情况下,在运行时,由超类和子类组成的对象与由单个类组成的具有典型 C++ 实现的对象之间没有区别。毕竟,创建子类最终会创建一个新类。因此,包含基类和子类的所有成员的单个类在运行时与单个类没有区别,只要所有类成员相同,按相同顺序排列,并且不涉及虚拟继承。

当然,编译器必须做更多的工作来跟踪超类和子类,所以编译器可能需要做一些额外的工作,跟踪两个单独的类,而不是之一。但除非代码库很大,否则我怀疑性能差异是否可以衡量。

【讨论】:

  • 糟糕。那应该是m_pointer,而不是m_object。我会修复代码。
  • 在这种情况下,您所拥有的将无法正常工作。子类不能构造超类的成员。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-21
  • 2011-11-12
  • 2014-01-05
相关资源
最近更新 更多