Why is "operator delete" called twice for my code when only one temporary is created.

Hi ppl :),

I have implemented "append" function for my string class in terms of operator "+=" as below :

append() :
1
2
3
4
  string& string::append(const string& rhs) {
    (*this) += rhs;
    return *this;
  }


operator += :
1
2
3
4
5
6
7
8
9
10
11
12
  string& string::operator += (const string& rhs) {
    std::unique_ptr<char[]> temp = std::make_unique<char[]>(sz_ + rhs.sz_ + 1);
    std::strcpy(temp.get(), ptr_.get());
    std::strcpy(temp.get() + sz_, rhs.ptr_.get());


    ptr_.reset(nullptr);
    sz_ += rhs.sz_;
    ptr_ = std::move(temp);

    return *this;
  }


string.h //partial code
1
2
3
4
5
6
7
  class string final {
    private:
      size_t sz_;  //string size
      std::unique_ptr<char[]> ptr_; //pointer to string data
    public:
      string();
      string(const string&);


[1] I am not able to understand why assembly code of append shows calling of operator delete twice ?

Here is the assembly code for append :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
kapil::string::append(kapil::string const&):
        push    r14
        push    r13
        mov     r13, rsi
        push    r12
        push    rbp
        push    rbx
        mov     rbp, QWORD PTR [rsi]
        mov     rbx, rdi
        add     rbp, QWORD PTR [rdi]
        lea     r14, [rbp+1]
        mov     rdi, r14
        call    operator new[](unsigned long)
        mov     r12, rax
        test    rbp, rbp
        js      .L122
        mov     rdx, r14
        xor     esi, esi
        mov     rdi, rax
        call    memset
.L122:
        mov     rbp, QWORD PTR [rbx+8]
        mov     rdi, r12
        mov     rsi, rbp
        call    strcpy
        mov     rdi, QWORD PTR [rbx]
        mov     rsi, QWORD PTR [r13+8]
        add     rdi, r12
        call    strcpy
        mov     QWORD PTR [rbx+8], 0
        mov     rdi, rbp
        call    operator delete[](void*)  //1st call
        mov     rdi, QWORD PTR [rbx+8]
        mov     rax, QWORD PTR [r13+0]
        mov     QWORD PTR [rbx+8], r12
        add     QWORD PTR [rbx], rax
        test    rdi, rdi
        je      .L123
        call    operator delete[](void*)  //2nd call
.L123:
        mov     rax, rbx
        pop     rbx
        pop     rbp
        pop     r12
        pop     r13
        pop     r14
        ret


I see that call to 2nd delete is done only when condition "je .L123" fails.

[2] What will be the scenario when both the delete calls will be executed and when only 1st one will be executed?

I'd really appreciate any inputs for [1] & [2].

Thanks
Last edited on
1. this calls delete on the old pointer value.
 
ptr_.reset(nullptr);


2. this calls delete on the old pointer value.
 
ptr_ = std::move(temp);


You don't need #1. Removing it will get rid of the extra call to operator delete.
Thanks a lot @Peter87 for the explanation :)
Topic archived. No new replies allowed.