Delete an object from a vector

2019-09-21 05:17发布

问题:

Step 1. Create an instance of a class

Step 2. Push this instance to a vector

Step 3. Call delete this; in a member method of an instance

Step 4. Everything is Ok

Step 5. Push something to the vector and get this

*** glibc detected *** ./app: double free or corruption (fasttop): 0x0000000001017930 ***
======= Backtrace: =========
/lib/libc.so.6(+0x71bd6)[0x7f607d60cbd6]
/lib/libc.so.6(cfree+0x6c)[0x7f607d61194c]
./app[0x40231c]
./app[0x402290]
./app[0x4053c0]
./app[0x4048fe]
./app[0x404246]
./app[0x403fe0]
./app[0x402400]
./app[0x4035cb]
./app[0x4034d3]
/lib/libpthread.so.0(+0x68ca)[0x7f607e2b78ca]
/lib/libc.so.6(clone+0x6d)[0x7f607d66a92d]
======= Memory map: ========
00400000-0040f000 r-xp 00000000 09:03 60427370                           /root/AHS/app
0060e000-0060f000 rw-p 0000e000 09:03 60427370                           /root/AHS/app
01017000-01038000 rw-p 00000000 00:00 0                                  [heap]
7f6074000000-7f6074021000 rw-p 00000000 00:00 0
7f6074021000-7f6078000000 ---p 00000000 00:00 0
7f607a595000-7f607a596000 ---p 00000000 00:00 0
7f607a596000-7f607ad96000 rw-p 00000000 00:00 0
7f607ad96000-7f607ad97000 ---p 00000000 00:00 0
7f607ad97000-7f607b597000 rw-p 00000000 00:00 0
7f607b597000-7f607b598000 ---p 00000000 00:00 0
7f607b598000-7f607bd98000 rw-p 00000000 00:00 0
7f607bd98000-7f607bd99000 ---p 00000000 00:00 0
7f607bd99000-7f607c599000 rw-p 00000000 00:00 0
7f607c599000-7f607c59a000 ---p 00000000 00:00 0
7f607c59a000-7f607cd9a000 rw-p 00000000 00:00 0
7f607cd9a000-7f607cd9b000 ---p 00000000 00:00 0
7f607cd9b000-7f607d59b000 rw-p 00000000 00:00 0
7f607d59b000-7f607d6f4000 r-xp 00000000 09:03 60425052                   /lib/libc-2.11.3.so
7f607d6f4000-7f607d8f3000 ---p 00159000 09:03 60425052                   /lib/libc-2.11.3.so
7f607d8f3000-7f607d8f7000 r--p 00158000 09:03 60425052                   /lib/libc-2.11.3.so
7f607d8f7000-7f607d8f8000 rw-p 0015c000 09:03 60425052                   /lib/libc-2.11.3.so
7f607d8f8000-7f607d8fd000 rw-p 00000000 00:00 0
7f607d8fd000-7f607d913000 r-xp 00000000 09:03 60425245                   /lib/libgcc_s.so.1
7f607d913000-7f607db12000 ---p 00016000 09:03 60425245                   /lib/libgcc_s.so.1
7f607db12000-7f607db13000 rw-p 00015000 09:03 60425245                   /lib/libgcc_s.so.1
7f607db13000-7f607db93000 r-xp 00000000 09:03 60425438                   /lib/libm-2.11.3.so
7f607db93000-7f607dd93000 ---p 00080000 09:03 60425438                   /lib/libm-2.11.3.so
7f607dd93000-7f607dd94000 r--p 00080000 09:03 60425438                   /lib/libm-2.11.3.so
7f607dd94000-7f607dd95000 rw-p 00081000 09:03 60425438                   /lib/libm-2.11.3.so
7f607dd95000-7f607de8b000 r-xp 00000000 09:03 60032880                   /usr/lib/libstdc++.so.6.0.13
7f607de8b000-7f607e08b000 ---p 000f6000 09:03 60032880                   /usr/lib/libstdc++.so.6.0.13
7f607e08b000-7f607e092000 r--p 000f6000 09:03 60032880                   /usr/lib/libstdc++.so.6.0.13
7f607e092000-7f607e094000 rw-p 000fd000 09:03 60032880                   /usr/lib/libstdc++.so.6.0.13
7f607e094000-7f607e0a9000 rw-p 00000000 00:00 0
7f607e0a9000-7f607e0b0000 r-xp 00000000 09:03 60425177                   /lib/librt-2.11.3.so
7f607e0b0000-7f607e2af000 ---p 00007000 09:03 60425177                   /lib/librt-2.11.3.so
7f607e2af000-7f607e2b0000 r--p 00006000 09:03 60425177                   /lib/librt-2.11.3.so
7f607e2b0000-7f607e2b1000 rw-p 00007000 09:03 60425177                   /lib/librt-2.11.3.so
7f607e2b1000-7f607e2c8000 r-xp 00000000 09:03 60425205                   /lib/libpthread-2.11.3.so
7f607e2c8000-7f607e4c7000 ---p 00017000 09:03 60425205                   /lib/libpthread-2.11.3.so
7f607e4c7000-7f607e4c8000 r--p 00016000 09:03 60425205                   /lib/libpthread-2.11.3.so
7f607e4c8000-7f607e4c9000 rw-p 00017000 09:03 60425205                   /lib/libpthread-2.11.3.so
7f607e4c9000-7f607e4cd000 rw-p 00000000 00:00 0
7f607e4cd000-7f607e4eb000 r-xp 00000000 09:03 60425293                   /lib/ld-2.11.3.so
7f607e6da000-7f607e6df000 rw-p 00000000 00:00 0
7f607e6e7000-7f607e6ea000 rw-p 00000000 00:00 0
7f607e6ea000-7f607e6eb000 r--p 0001d000 09:03 60425293                   /lib/ld-2.11.3.so
7f607e6eb000-7f607e6ec000 rw-p 0001e000 09:03 60425293                   /lib/ld-2.11.3.so
7f607e6ec000-7f607e6ed000 rw-p 00000000 00:00 0
7fff4ee3b000-7fff4ee50000 rw-p 00000000 00:00 0                          [stack]
7fff4efff000-7fff4f000000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Aborted

Could someone please tell me, what is this, why this occurs and how do I fix it?

回答1:

Doing delete this for an object belonging to a vector you are making two big mistakes:

  1. it's the vector that manages the memory where that instance is stored (it allocates it, deallocates it, ...), so you shouldn't mess with it. In other words, since you don't own that memory you must leave it alone.
  2. delete is a correct match if the object was allocated with new - but the object managed by the vector is not allocated like that; instead, vector grabs a chunk of memory from the allocator (as big as it thinks it's sensible) and copies there the elements that are pushed into it using placement new; so, not only you are freeing memory that you don't own, you are also using the wrong method to free it.

If you need to remove an element from a vector, just use the vector::erase method.



回答2:

It's because you freed memory you didn't own. The vector owns the memory containing its contents.

delete this; is like taking a rental car to the salvage yard when you're done with it. Don't do that, the rental company expects it back!

Be careful of the difference between owning memory, and merely having control of it loaned to you.



回答3:

If you do delete this in any method, you have to be sure that no one else calls any method ( for that matter any code) of the instance after that statement. This includes the destructor.

When you push the instance into a vector, while being destroyed, the vector calls the destructor for the instance, hence the double free

If you need a vector, you can push pointers to the instance and it would be fine.

However, as others have said DO NOT use delete this unless absolutely necessary

You would also have the problems if you just create an local instance of the class in a function. Most likely you did not see this behavior because your program finished before the scope of the local variable ended. If you tried this :

void func() {
    MyClass myClass;
    myClass.theBadFunc();
}

When this returns, you will have a core dump.



回答4:

Does this resemble the code that you're describing?

struct MyClass {
    void f() { delete this; }
};

int main() {
    MyClass c;
    std::vector<MyClass> v;
    v.push_back(c);
    c.f();
    return 0;
}

The vector is irrelevant. The problem is that delete this calls the destructor for c and frees the memory where c was built. That memory is on the stack, and cannot be freed. Don't ever delete stack objects. The compiler generates code to clean them up when they go out of scope, in this case, at the end of main.