user2673108
user2673108

Reputation: 309

dynamic memory management scenario

Should one use dynamic memory allocation when one knows that a variable will not be needed before it goes out of scope?

For example in the following function:

void func(){
int i =56;
//do something with i, i is not needed past this point
for(int t; t<1000000; t++){
//code
}
}

say one only needed i for a small section of the function, is it worthwhile deleting i as it is not needed in the very long for loop?

Upvotes: 0

Views: 106

Answers (1)

ilent2
ilent2

Reputation: 5241

As Borgleader said:

A) This is micro (and most probably premature) optimization, meaning don't worry about it. B) In this particular case, dynamically allocation i might even hurt performance. tl;dr; profile first, optimize later

As an example, I compiled the following two programs into assembly (using g++ -S flag with no optimisation enabled).

Creating i on the stack:

int main(void)
{
    int i = 56;
    i += 5;

    for(int t = 0; t<1000; t++) {}

    return 0;
}

Dynamically:

int main(void)
{
    int* i = new int(56);
    *i += 5;
    delete i;

    for(int t = 0; t<1000; t++) {}

    return 0;
}

The first program compiled to:

    movl    $56, -8(%rbp)           # Store 56 on stack (int i = 56)
    addl    $5, -8(%rbp)            # Add 5 to i (i += 5)
    movl    $0, -4(%rbp)            # Initialize loop index (int t = 0)
    jmp .L2                         # Begin loop (goto .L2.)
.L3:
    addl    $1, -4(%rbp)            # Increment index (t++)
.L2:
    cmpl    $999, -4(%rbp)          # Check loop condition (t<1000)
    setle   %al
    testb   %al, %al
    jne .L3                         # If (t<1000) goto .L3.
    movl    $0, %eax                # return 0

And the second:

    subq    $16, %rsp               # Allocate memory (new)
    movl    $4, %edi
    call    _Znwm
    movl    $56, (%rax)             # Store 56 in *i
    movq    %rax, -16(%rbp)
    movq    -16(%rbp), %rax         # Add 5
    movl    (%rax), %eax
    leal    5(%rax), %edx
    movq    -16(%rbp), %rax
    movl    %edx, (%rax)
    movq    -16(%rbp), %rax         # Free memory (delete)
    movq    %rax, %rdi
    call    _ZdlPv
    movl    $0, -4(%rbp)            # Initialize loop index (int t = 0)
    jmp .L2                         # Begin loop (goto .L2.)
.L3:
    addl    $1, -4(%rbp)            # Increment index (t++)
.L2:
    cmpl    $999, -4(%rbp)          # Check loop condition (t<1000)
    setle   %al
    testb   %al, %al
    jne .L3                         # If (t<1000) goto .L3.
    movl    $0, %eax                # return 0

In the above assembly output, you can see strait away that there is a significant difference between the number of commands being executed. If I compile the same programs with optimisation turned on. The first program produced the result:

    xorl    %eax, %eax                  # Equivalent to return 0;

The second produced:

    movl    $4, %edi
    call    _Znwm
    movl    $61, (%rax)                 # A smart compiler knows 56+5 = 61
    movq    %rax, %rdi
    call    _ZdlPv
    xorl    %eax, %eax
    addq    $8, %rsp

With optimisation on, the compiler becomes a pretty powerful tool for improving your code, in certain cases it can even detect that a program only returns 0 and get rid of all the unnecessary code. When you use dynamic memory in the code above, the program still has to request and then free the dynamic memory, it can't optimise it out.

Upvotes: 2

Related Questions