C++多态性能测试:CRTP vs std::variant vs virtual

本文对比了C++中虚函数、std::variant和CRTP在多态性能上的差异,通过GCC和Clang编译器的测试结果显示,std::variant在某些场景下与虚函数性能相近,但与CRTP有显著差距,尤其是在Clang中CRTP配合std::variant时性能下降。
摘要由CSDN通过智能技术生成

C++多态性能测试:CRTP vs std::variant vs virtual

多态是面向对象编程的一个重要概念,它使得单一接口能够代表不同的类型。C++提供了几种实现多态性的方式,本文将会讨论三种场景的多态:

  1. 虚函数:在C++中实现多态性的传统方式是使用虚函数。这涉及使用基类和派生类来实现特定的实现。

  2. std::variant:在C++17中引入的std::variant,它实现了一种无需继承的多态性。

  3. CRTP(Curiously Recurring Template Pattern):CRTP是一种比较特殊的技术,它通过模板的奇特递归模式实现多态性。

测试的组合场景如下:

  • 单纯crtp

  • crtp + std::variant

  • virtual

  • std::variant + std::visit

  • std::variant + std::get_if

  • std::variant + std::holds_alternative

使用的编译器:

  • gcc 13.2

  • clang17.0

完整测试代码已放置星球,这里贴一下关键代码(见文末)。

测试结果1:gcc编译,可以看到virtual与std::variant性能差别不大,但是与crtp差别非常大。

ad9bf6391e8ea8e8f2a7f22bb176dc4b.png

测试结果2:clang编译,总体趋势类似gcc编译,只有crtp + std::variant性能明显回退,这个可能也是由于这里用了std::visit导致。

8770f4eee28b530498c9dcdbc59bfd81.png

在A Tour of C++书中提到:

This is basically equivalent to a virtual function call, but potentially faster. As with all claims of performance, this ‘‘potentially faster’’ should be verified by measurements when performance is critical. For most uses, the difference in performance is insignificant.

与本次测试基本符合。

关键测试代码:

class Shape {
public:
    virtual ~Shape() = default;
    virtual double area() const = 0;
};

class Circle : public Shape
class Rectangle : public Shape
  

  
// virtual
static void BM_VirtualFunction(benchmark::State& state) {
    std::vector<std::unique_ptr<Shape>> shapes;
    shapes.reserve(1000);

    for (int i = 0; i < 1000; ++i) {
        if (i % 2 == 0) {
            shapes.emplace_back(std::make_unique<Circle>(5.0));
        } else {
            shapes.emplace_back(std::make_unique<Rectangle>(4.0, 6.0));
        }
    }

    for (auto _ : state) {
        double totalArea = 0.0;
        for (const auto& shape : shapes) {
            totalArea += shape->area();
        }
        benchmark::DoNotOptimize(totalArea);
    }
}
BENCHMARK(BM_VirtualFunction);

static void BM_VariantVisit(benchmark::State& state) {
    std::vector<std::variant<Circle, Rectangle>> shapes;
    shapes.reserve(1000);

    for (int i = 0; i < 1000; ++i) {
        if (i % 2 == 0) {
            shapes.emplace_back(Circle(5.0));
        } else {
            shapes.emplace_back(Rectangle(4.0, 6.0));
        }
    }

    for (auto _ : state) {
        double totalArea = 0.0;
        for (const auto& s : shapes) {
            totalArea += std::visit([](const auto& shape) { return shape.area(); }, s);
        }
        benchmark::DoNotOptimize(totalArea);
    }
}
static void BM_CRTPVariant(benchmark::State& state) {
    std::vector<ShapeVariant> shapes;
    shapes.reserve(1000);

    for (int i = 0; i < 1000; ++i) {
        if (i % 2 == 0) {
            shapes.emplace_back(crtp_light::Circle(5.0));
        } else {
            shapes.emplace_back(crtp_light::Rectangle(4.0, 6.0));
        }
    }

    for (auto _ : state) {
        double totalArea = 0.0;
        for (const auto& s : shapes) {
            totalArea += std::visit([](const auto& shape) { return shape.area(); }, s);
        }
        benchmark::DoNotOptimize(totalArea);
    }
}
BENCHMARK(BM_CRTPVariant);

// ...

学习更多知识,获取源码👇

a193b84e6c4aecbafc173f955e112796.jpeg

往期回顾:

热度更新,手把手实现工业级线程池

秒杀面试题:深入final,掌握C++性能优化

C++20:从0到1学懂concept

5f50b491ecde16e0602046fe0f356913.jpeg

  • 21
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值