【问题标题】:std::unique_ptr operator[] vs. raw ptr dynamic array operator[]std::unique_ptr operator[] 与原始 ptr 动态数组 operator[]
【发布时间】:2021-04-14 23:45:17
【问题描述】:

我有以下代码示例:

void foo(int size)
{
    std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t>(size);
    for(int i = 0; i < size; i += 2)
    {
        data[i] = 1;
        data[i + 1] = 2;
    }
}

实际代码会进行实际计算,但这对于这个问题并不重要,为了简单起见已将其删除。

在启用优化的情况下编译和运行此代码时,一切正常且运行迅速。 但是,在没有任何优化的情况下运行时,此代码比以下代码慢得多:

void foo(int size)
{
    std::unique_ptr<uint8_t[]> data = std::make_unique<uint8_t>(size);
    uint8_t* dataPtr = data.get();

    for(int i = 0; i < size; i += 2)
    {
        dataPtr[i] = 1;
        dataPtr[i + 1] = 2;
    }
}

为了进一步研究这一点,我通过编译器资源管理器 (godbolt.org) 使用此动态数组运行了索引运算符的多个变体。 使用 clang 和 -O3 优化进行编译,所有变体都会产生相同的程序集。 但是,在没有任何优化的情况下进行编译,unique_ptr only 样本调用了 unique_ptr operator[],这似乎导致了速度变慢。

为什么没有优化的 unique_ptr 的 operator[] 会慢得多?从文档中我看到 operator[] 应该等同于 unique_ptr.get()[]。 它是否在没有优化的情况下进行了一些安全检查?如果有,有哪些?

【问题讨论】:

  • 您看到的减速有多大? “很多”非常模糊。

标签: c++ performance optimization indexing unique-ptr


【解决方案1】:

如果没有优化,调用operator[] 并将索引作为参数传递会产生开销。通过优化,编译器可以内联整个函数以避免调用函数的开销(并且由于它导致相同的汇编,您已经知道性能将是相同的)。

这是在没有优化的情况下进行分析/基准测试会导致错误结果的众多原因之一:零成本抽象的成本通常不会在您的生产构建中产生。

【讨论】:

  • 你检查operator[]是否有调试检查?这是有道理的,这里不作说明。
  • @Yakk-AdamNevraumont libstdc++ checks that get() != nullptr 如果_GLIBCXX_DEBUG 在包含任何标题之前定义(此处不是这种情况),libc++ has no checkMicrosoft's STL also has no check
  • 无论哪种方式,如果优化改变了行为,您应该花时间进行生产中使用的优化
  • 有时调试性能很重要;如果调试速度太慢,程序可能会变得无法使用,您需要使用该程序进行调试。 OP 询问为什么速度较慢;添加您的发现以改进答案!
猜你喜欢
  • 1970-01-01
  • 2013-02-18
  • 2022-08-04
  • 2021-04-11
  • 2021-12-10
  • 1970-01-01
相关资源
最近更新 更多