【问题标题】:Why is assignment slower when there's an implicit conversion?为什么存在隐式转换时赋值速度较慢?
【发布时间】:2015-03-26 08:42:05
【问题描述】:

如果有类似的问题,请指导我,我安静地搜索了一段时间,但没有找到任何东西。

背景:

我只是在玩耍,发现了一些我无法完全解释的行为...... 对于原始类型,看起来当存在隐式转换时,赋值运算符 = 与显式赋值相比需要更长的时间。

int iTest = 0;
long lMax = std::numeric_limits<long>::max();
for (int i=0; i< 100000; ++i)
{
    // I had 3 such loops, each running 1 of the below lines.
    iTest = lMax;
    iTest = (int)lMax;
    iTest = static_cast<int>(lMax);
}

结果是 c 样式转换和 c++ 样式 static_cast 平均执行相同(每次不同,但没有明显差异)。并且它们都优于隐式分配。

Result:
iTest=-1, lMax=9223372036854775807
(iTest = lMax) used 276 microseconds

iTest=-1, lMax=9223372036854775807
(iTest = (int)lMax) used 191 microseconds

iTest=-1, lMax=9223372036854775807
(iTest = static_cast<int>(lMax)) used 187 microseconds

问题:

为什么隐式转换会导致更大的延迟?我可以猜测它必须在int溢出的分配中检测到,因此调整为-1。但是任务中到底发生了什么?

谢谢!

【问题讨论】:

  • 我猜你的基准测试有缺陷。
  • 尝试改变测试的顺序。也许它总是第一个花费时间最长的。此外,这里看起来 100000 太小了。让测试更长。

标签: c++ casting static-cast


【解决方案1】:

如果你想知道为什么某事会在幕后发生,最好的地方是……等待它……幕后 :-)

这意味着检查编译器生成的汇编语言。

最好将 C++ 环境视为运行 C++ 代码的抽象机器。标准(大部分)规定行为,而不是实施细节。一旦你离开了标准的界限并开始思考下面会发生什么,C++源代码就没有什么帮助了——你需要检查计算机的实际代码运行时,编译器输出的东西(通常是机器码)。

可能是编译器丢弃了循环,因为它每次都在计算相同的东西,所以只需要执行一次。如果它可以确定您不使用结果,它可能会完全丢弃代码。

很久以前,VAX Fortran 编译器(我确实说过 很多 个月)在给定的基准测试中超过了它的竞争对手几个数量级。

正是出于那个确切的原因。它已经确定没有使用循环的结果,因此优化了整个循环不存在。


您可能需要注意的另一件事是测量工具本身。当您谈论 1/10,000th 秒的持续时间时,您的结果可能会淹没一点点噪音。

有一些方法可以减轻这些影响,例如确保您正在测量的东西是实质性的(例如超过十秒),或者使用统计方法来消除任何噪音。

但最重要的是,它可能是导致您看到的结果的测量方法。

【讨论】:

  • “最好将 C++ 环境视为运行 C++ 代码的虚拟机。” -- Err,不,不是,因为它不是...
  • @DevSolar,来自 C++11 1.9:本国际标准中的语义描述定义了一个参数化的非确定性抽象机。本国际标准对一致性实现的结构没有要求。特别是,它们不需要复制或模仿抽象机器的结构。相反,需要符合要求的实现来模拟(仅)抽象机的可观察行为,如下所述。
  • 虽然我承认我记错了这句话,所以我改变了答案以使用更好的短语“抽象机器”。
  • 我理解标准措辞的概念。但是,虽然它有助于定义语言,但没有关于特定实现的“虚拟”或“抽象”。这就是为什么我对 VM 术语有疑问。接下来我们将直接执行的机器代码称为“字节码”,而 CPU 则是 JIT 编译器……啊,算了。祝你今天过得愉快! ;-)
  • 我使用这个短语是因为没有指定实现。因此,它应该被视为关于 C++ 本身的问题,而不是它的某些实现。我会尽力澄清。
【解决方案2】:
#include <limits>

int iTest = 0;
long lMax = std::numeric_limits<long>::max();

void foo1()
{
  iTest = lMax;
}

void foo2()
{
  iTest = (int)lMax;
}

void foo3()
{
  iTest = static_cast<int>(lMax);
}

使用-O3 使用 GCC 5 编译产生:

__Z4foo1v:
    movq    _lMax(%rip), %rax
    movl    %eax, _iTest(%rip)
    ret

__Z4foo2v:
    movq    _lMax(%rip), %rax
    movl    %eax, _iTest(%rip)
    ret

__Z4foo3v:
    movq    _lMax(%rip), %rax
    movl    %eax, _iTest(%rip)
    ret

它们都完全相同。

由于您没有提供完整的示例,我只能猜测差异是由于您没有向我们展示的东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-03
    • 2022-11-24
    相关资源
    最近更新 更多