除了复制删除之外,还有什么机制可以优化C++中的过度构造?

除了复制删除之外,还有什么机制可以优化C++中的过度构造?,c++,constructor,compiler-optimization,C++,Constructor,Compiler Optimization,我的函数有一个switch case语句。有一个对象仅在其某些分支中使用。我是否可以将此对象的初始化放在switch case语句之前,并期望只有在实际使用时才会创建它 我的意思是,这两种代码在性能上是否有任何差异: void someFunc( SomeEnum someEnum, Parameter parameter ) { Object object( parameter ); switch( someEnum ) { case SomeEnum

我的函数有一个switch case语句。有一个对象仅在其某些分支中使用。我是否可以将此对象的初始化放在switch case语句之前,并期望只有在实际使用时才会创建它

我的意思是,这两种代码在性能上是否有任何差异:

void someFunc( SomeEnum someEnum, Parameter parameter )
{
    Object object( parameter );
    
    switch( someEnum )
    {
    case SomeEnum::A:
        otherFunc( object );
        break;
        
    case SomeEnum::B:
        otherFunc( object );
        break;
        
    case SomeEnum::C:
        anotherFunc();
        break;
    }
}
还有这个:

void someFunc( SomeEnum someEnum, Parameter parameter )
{   
    switch( someEnum )
    {
    case SomeEnum::A: {
            Object object( parameter );
            otherFunc( object );
        }
        break;
        
    case SomeEnum::B: {
            Object object( parameter );
            otherFunc( object );
        }
        break;
        
    case SomeEnum::C:
        anotherFunc();
        break;
    }
}

它取决于编译器和对象。在前一个例子中,像msvc这样的坏编译器实际上会分配更少的堆栈空间,而在后一个例子中会分配N倍的堆栈空间。但是,如果对象的构造函数做了一些繁重的工作和/或动态分配了大量内存,则后者更可取,因为只有在达到某个条件时才会调用构造函数。

这取决于编译器和对象。在前一个例子中,像msvc这样的坏编译器实际上会分配更少的堆栈空间,而在后一个例子中会分配N倍的堆栈空间。但是,如果Object的构造函数做了一些繁重的工作和/或动态分配了大量内存,则后者更可取,因为只有在达到某个情况时才会调用构造函数。

可能是因为此示例过于简化,但是拥有这个对象与代码的操作几乎无关——它的值永远不会被使用。因此,创建一个临时变量,而不是一个没有任何重要用途的命名变量:

otherFunc(Object());
当然,如果otherFunc希望能够修改其参数,那么这将不起作用

假设otherFunc不修改其参数,另一种可能性是使用默认参数:

void otherFunc(Object object = Object());
otherFunc();
现在,无需显式参数即可调用它:

void otherFunc(Object object = Object());
otherFunc();

编译后的代码将在调用时生成一个临时对象。

可能是因为这个示例过于简化,但拥有该对象与代码的操作几乎无关——它的值从未被使用过。因此,创建一个临时变量,而不是一个没有任何重要用途的命名变量:

otherFunc(Object());
当然,如果otherFunc希望能够修改其参数,那么这将不起作用

假设otherFunc不修改其参数,另一种可能性是使用默认参数:

void otherFunc(Object object = Object());
otherFunc();
现在,无需显式参数即可调用它:

void otherFunc(Object object = Object());
otherFunc();
编译后的代码将在调用点生成一个临时值

我是否可以将此对象的初始化放在switch case语句之前,并期望只有在实际使用时才会创建它

< C++ >没有任何机制,允许在文本中声明的对象只根据运行时信息实际创建。 现在,如果对象是平凡的,或者如果编译器可以看到该对象的构造函数/析构函数除了操纵该对象的状态外没有任何可见的副作用,那么编译器可以根据“好像”规则有效地将第一个代码转换为第二个代码。但这只是因为没有任何东西可以检查对象是否已创建

请注意,可见的副作用包括调用内存分配函数、打开文件或其他操作系统级别的重量级活动。IE:正是从性能的角度来看,你可能特别关注的事情。所以,如果这真的会影响性能,那么编译器就很有可能无法将其视为一种损失

因此,如果您明确需要延迟构建,那么您应该在代码中明确说明这一点

我是否可以将此对象的初始化放在switch case语句之前,并期望只有在实际使用时才会创建它

< C++ >没有任何机制,允许在文本中声明的对象只根据运行时信息实际创建。 现在,如果对象是平凡的,或者如果编译器可以看到该对象的构造函数/析构函数除了操纵该对象的状态外没有任何可见的副作用,那么编译器可以根据“好像”规则有效地将第一个代码转换为第二个代码。但这只是因为没有任何东西可以检查对象是否已创建

请注意,可见的副作用包括调用内存分配函数、打开文件或其他操作系统级别的重量级活动。IE:正是从性能的角度来看,你可能特别关注的事情。所以,如果这真的会影响性能,那么编译器就很有可能无法将其视为一种损失


所以,如果您明确需要延迟构建,那么应该在代码中明确说明。

就像规则。。。但是对象参数不应该有副作用。你确定这是一个瓶颈吗?@Jarod42对不起,太过了
我把这部分删掉了。修正了。@bolov是的,差不多。我还没有做过基准测试,但这将是一个在一系列非常频繁执行的方法中反复出现的模式。@Forthleft:是的,差不多。我还没有完成基准测试,那么你还没有确定这是一个瓶颈;你是在假设它可能是一个。。。但是Object参数不应该有副作用。你确定这是一个瓶颈吗?@Jarod42抱歉,忽略了这一部分。修正了。@bolov是的,差不多。我还没有做过基准测试,但这将是一个在一系列非常频繁执行的方法中反复出现的模式。@Forthleft:是的,差不多。我还没有完成基准测试,那么你还没有确定这是一个瓶颈;你是在假设它可能是一个。像msvc这样糟糕的编译器。。。我在MSVC上抨击了C++的一致性,在过去实现新的标准特性方面落后了,但是甚至忽略了它们现在已经走了多远,甚至如何引导一些C++新特性,称它为一个坏编译器太多了。你对此有什么来源吗?我会引用它的源代码;但它是封闭源代码,所以我不能。此外,我建议你在这里查看我最近的问题。这是一个活生生的例子,说明了为什么像clang这样的编译器应该被优先使用。@Hi IloveSO:我看了这个问题,但还没有确定正确答案在这种情况下是什么,就像标准所说的应该发生什么一样。我对模板的复杂性知之甚少,无法说出标准对这一问题的看法。除非有人权衡正确的行为应该是什么,否则这个问题很难证明任何编译器是好是坏。所有的编译器都有bug,指出一种情况下,clang是正确的,即使这似乎不是证据,也不是真正相关的,因为另一种情况下,只有clang失败…一个像msvc一样糟糕的编译器。。。我在MSVC上抨击了C++的一致性,在过去实现新的标准特性方面落后了,但是甚至忽略了它们现在已经走了多远,甚至如何引导一些C++新特性,称它为一个坏编译器太多了。你对此有什么来源吗?我会引用它的源代码;但它是封闭源代码,所以我不能。此外,我建议你在这里查看我最近的问题。这是一个活生生的例子,说明了为什么像clang这样的编译器应该被优先使用。@Hi IloveSO:我看了这个问题,但还没有确定正确答案在这种情况下是什么,就像标准所说的应该发生什么一样。我对模板的复杂性知之甚少,无法说出标准对这一问题的看法。除非有人权衡正确的行为应该是什么,否则这个问题很难证明任何编译器是好的还是坏的。所有的编译器都有bug,指向一个案例,其中clang是正确的,即使这似乎不是证据,也不是真的相关,因为其他的也可以指向只有clang失败的案例。。。