编写代码时,我是否必须考虑编译后的机器代码?


20

例如,我有以下代码:

auto z = [](int x) -> int {
    if (x > 0) {
        switch (x) {
            case 2: return 5;
            case 3: return 6;
            default: return 1;
            }
        }
    return 0;
    };

后来我多次打电话给我。在asm代码中,我看到了使用lambda进行的外部调用。因此,也许我在元编程中获胜,但在asm调试和性能方面是否会输?我是否应该避免使用现代语言功能,宏和其他元编程方面,以确保性能和调试简便性?


1
根据编译器的版本及其捆绑的标准库,lambda的实现可能确实效率低下。请参阅Stackoverflow上的此问题。但是,改进的责任应该在于编译器供应商。
rwong

15
除非您对性能至关重要,否则不需要调试汇编代码。另外,“干净的代码”!=“良好的性能”。
2013年

请修正您的缩进。我尝试这样做,但似乎您不能只编辑空格。
ChristofferHammarström'13年

3
@Heather:您似乎正在使用Ratliff样式,这是我以前从未见过的,很难读懂。它当然是鲜为人知的之一。我的印象是您没有正确缩进。没关系,如果您觉得它可读,我只是不同意。
ChristofferHammarström'13年

1
if是示例代码完全多余的,虽然编译器可能会赶上没有理由引诱坏的分支预测。
dmckee

Answers:


59

编写代码时,我是否必须考虑编译后的机器代码?

,不是在您第一次编写代码时,也不会遇到任何实际的,可衡量的性能问题。对于大多数任务,这是标准情况。过早地考虑优化被称为“过早优化”,而D. Knuth称其为“万恶之源”是有充分理由的。

是的,当您测量实际的,可证明的性能瓶颈时,您将特定的lambda构造确定为根本原因。在这种情况下,记住Joel Spolsky的“泄漏抽象定律”并考虑在asm级别可能发生的事情是一个好主意。但是要当心,当您用“不是那么现代的”语言构造替换lambda构造时(至少在使用像样的C ++编译器时),性能提升会多么小。


2
+1简洁,准确且易于使用的普通文档,很高兴我们能在这里陪伴您。
吉米·霍法2013年

同意,非常明确的答案。
cnd

8

在lambda和函子类之间进行选择是一种折衷。

通过最小化样板的数量并允许将与概念相关的代码以内联方式写入(即将或以后利用)函数中,lambda的收益主要是语法上的。

从性能角度来看,这并不比functor类差,functor类是包含单个“方法”的C ++结构或类。实际上,编译器对待lambda的方式与在后台编译器生成的仿函数类相同。

// define the functor method somewhere
struct some_computer_generated_gibberish_0123456789
{
    int operator() (int x) const
    {
        if (x == 2) return 5;
        if (x == 3) return 6;
        return 0;
    }
};

// make a call
some_computer_generated_gibberish_0123456789 an_instance_of_0123456789;
int outputValue = an_instance_of_0123456789(inputValue);

在您的代码示例中,就性能而言,它与函数调用没有什么不同,因为该函子类恰好没有状态(因为它具有空的capture子句),因此不需要分配,构造函数或销毁。

int some_computer_generated_gibberish_0123456789_method_more_gibberish(int x)
{
    if (...) return ...;
    return ...;
}

使用反汇编器调试任何不平凡的C ++代码始终是一项艰巨的任务。无论是否使用lambda都是如此。这是由于C ++编译器进行了复杂的代码优化而导致的,从而导致重新排序,交织和消除无效代码。

名称处理方面有些令人不快,调试器对lambda的支持仍处于起步阶段。只能希望调试器支持会随着时间的推移而改善。

当前,调试Lambda代码的最佳方法是使用支持在源代码级别设置断点的调试器,即通过指定源文件名和行号。


3

要添加@DocBrown的答案,请记住,这些天CPU很便宜,但人工却很昂贵。

在程序的总成本中,与维护成本相比,硬件通常是微不足道的,维护成本是典型项目中最昂贵的部分(甚至比其开发成本还要高)。

因此,您的代码需要在所有其他方面优化维护,除非性能至关重要(甚至需要考虑维护)。


仅部分正确。如果您的代码运行O(n ^ 2)(二次),并且可以更好地说O(log(n))(对数),则更改代码后,硬件将永远不会有太大的性能提升。在原始海报指定的情况下,这是极不可能的。
gnash117

@ gnash117 —是的,如果代码要运行多次,那是对的;感谢您指出这一点。在这种情况下,清楚地记录代码将在保持性能的同时保持其可维护性。
帕迪·兰道

“劳动力昂贵”-是的。客户的时间很重要,而且通常很昂贵。
Cerad
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.