Should I create object on a free store only for one call?

时间:2017-07-12 08:21:21

标签: c++ memory-management heap-memory

Assuming that code is located inside if block, what are differences between creating object in a free store and doing only one call on it:

    auto a = aFactory.createA();
    int result = a->foo(5);

and making call directly on returned pointer?

    int result = aFactory.createA()->foo(5);

Is there any difference in performance? Which way is better?

#include <iostream>
#include <memory>

class A 
{
public:
    int foo(int a){return a+3;}
};

class AFactory
{
public:    
    std::unique_ptr<A> createA(){return std::make_unique<A>();}
};

int main()
{
    AFactory aFactory;
    bool condition = true;
    if(condition)
    {
        auto a = aFactory.createA();
        int result = a->foo(5);   
    }
}

2 个答案:

答案 0 :(得分:2)

here。即使禁用了优化,两个版本的代码也没有区别。

将gcc7.1与-std=c++1z -O0

一起使用
    auto a = aFactory.createA();
    int result = a->foo(5);  

编译为:

    lea     rax, [rbp-24]
    lea     rdx, [rbp-9]
    mov     rsi, rdx
    mov     rdi, rax
    call    AFactory::createA()
    lea     rax, [rbp-24]
    mov     rdi, rax
    call    std::unique_ptr<A, std::default_delete<A> >::operator->() const
    mov     esi, 5
    mov     rdi, rax
    call    A::foo(int)
    mov     DWORD PTR [rbp-8], eax
    lea     rax, [rbp-24]
    mov     rdi, rax
    call    std::unique_ptr<A, std::default_delete<A> >::~unique_ptr()

int result = aFactory.createA()->foo(5);

    lea     rax, [rbp-16]
    lea     rdx, [rbp-17]
    mov     rsi, rdx
    mov     rdi, rax
    call    AFactory::createA()
    lea     rax, [rbp-16]
    mov     rdi, rax
    call    std::unique_ptr<A, std::default_delete<A> >::operator->() const
    mov     esi, 5
    mov     rdi, rax
    call    A::foo(int)
    mov     DWORD PTR [rbp-8], eax
    lea     rax, [rbp-16]
    mov     rdi, rax
    call    std::unique_ptr<A, std::default_delete<A> >::~unique_ptr()

所以他们几乎完全相同。

当您意识到两个版本之间的唯一区别是在第一个版本中我们将名称分配给对象时,这个结果是可以理解的,而在第二个版本中我们使用未命名的版本。除此之外,它们都是在堆上创建的,并以相同的方式使用。因为变量名对编译器没有任何意义 - 它只对代码阅读器有用 - 它将两者视为相同。

答案 1 :(得分:1)

在您的简单情况下,它不会产生任何影响,因为(主要)功能在创建和使用a后立即结束。

如果会有更多的代码行,a对象的销毁将发生在if的{​​{1}}块的末尾,而在一行的情况下它会变为在那条单线的尽头被破坏了。但是,如果更复杂的main的析构函数会对此产生影响,那将是糟糕的设计。

由于编译器优化,应始终通过在具体代码上使用分析器进行测试来回答性能问题。