【问题标题】:Overhead enforcing member function implementation开销强制成员函数实现
【发布时间】:2020-05-04 02:45:39
【问题描述】:

我有一个Base 课程和一个Derived 课程。 Base 类的唯一目标是确保 Derived 实现成员函数。

struct Base
{
    virtual void f() = 0;
};

struct Derived : Base
{
    void f() override final {}
};

我没有多态地使用这个类,也就是说,我只是在堆栈上实例化 Derived 类型的对象,如下所示:

Derived obj;

我需要这样做数百万次。

编辑:只有少数实例同时存在(没有堆栈溢出)。

这里是否创建了vtable(我猜是在编译期间)?是否创建了vtable 对我来说是否重要,因为我不使用它(或者我不使用它)?我应该考虑使用这种设计有什么开销吗?如果Derived 没有实现f(),也许还有另一种方法可以确保编译器抱怨?

【问题讨论】:

  • 这能回答你的问题吗? Is final used for optimization in C++?
  • 为什么不在Base 中直接省略f()?如果Derived 没有实现f()obj.f() 将无法编译。
  • 您可以查看Derived的大小。在我的例子中,it was 8 bytes,这意味着一个 vtable 指针。 如果Derived 没有实现f(),也许还有另一种方法可以确保编译器报错? 当然,如果您为Derived 的任何对象调用f,而没有f提供,编译将失败。另请参阅:Is it possible to write a template to check for a function's existence?。您可以编写一个元函数来检查存在 f 并使用它,例如,使用静态断言以获得更好的诊断。
  • 如果你不使用多态类,你可以使用 CRTP 模式,它 a) 没有额外的神秘通道和口哨将确保需要实现的方法 b) 不使用 vtable 并可能导致优化来电
  • @Evg 好点,但想象一下这段代码在一个库中并且只能从另一个库调用。

标签: c++ compiler-optimization virtual-functions vtable dynamic-dispatch


【解决方案1】:

这里是否创建了一个 vtable ?

是的,因为您有 virtual 成员函数。

是否创建了 vtable 对我有影响吗,因为我不使用它

由于您不使用它,它仍然很重要,它会增加您的 Derived 结构的大小。
在这里,您的 Derived 结构的大小为 8。但如果没有 vtable,它将大小为 1。

如果Derived 没有实现f(),也许还有另一种方法可以确保编译器报错?

老实说,我认为您的解决方案使用Base 作为接口来强制每个派生类实现f() 函数,因为它是使用的确切用例接口


但是如果Derived 结构的大小是一个问题(因为你说你想实例化它数百万次),也许你会对std::is_member_function_pointer 类型特征感兴趣。

我不知道您打算如何实例化您的 Derived 结构,因此我无法提供完全适合您需求的代码。
但是我正在考虑的想法等同于以下(通用示例):

 #include <type_traits>

template <typename T>
void instantiate_a_lot_of_times(std::size_t nb_times)
{
    // Check if the f() member function exists
    static_assert(std::is_member_function_pointer<decltype(&T::f)>::value, "Error: The T::f() member function must be defined");

    for(std::size_t i = 0; i < nb_times; ++i)
    {
        T t;
        // Do something with t
    }
}

但请记住,这种方法存在延迟检查的缺点。
遇到结构体定义但评估static_assert时编译不会失败。

【讨论】:

  • 我对我的问题添加了一个编辑:同时只存在几个实例。
  • 我不认为在堆栈上分配 8 或 1 对性能很重要,是吗?
  • @mfnx 在这种情况下,我认为您的方法应该没问题/是好的方法。我对10e7 迭代做了一些基准测试(1 次迭代:实例化 3 个Derived 对象并在每个实例上调用f())。使用和不使用 vtable(8 号与 1 号),我没有看到任何显着的时间差异(在我的机器上是百分之几秒,这不是很强大)。
猜你喜欢
  • 1970-01-01
  • 2011-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多