2

I read the smart pointer from C++ Primer 5 Edition. In section 12.1.3, some description goes like

The smart pointer types define a function named 'get' that returns a built-in pointer to the object that the smart pointer is managing. The function is intended for cases when we need to pass a built-in pointer to code that can't use a smart pointer. The code that uses the return from 'get' must not 'delete' that pointer.

A example is also given below the description

shared_ptr<int> p(new int(42));       // reference count is 1
int *q = p.get();
{//new block
//undefined:two independent shared_ptr point to the same memory
      shared_ptr<int>(q);
}//block ends, q is destroyed ,and the memory to which q points is freed
int foo = *q; //undefined; the memory to which p points was freed

I can understand the explanation above clearly. BUT, when I come across Exercise 12.13, I am a little bit confused.

#include<iostream>
#include<memory>
using namespace std;

int main(){
        auto sp = make_shared<int>();
        auto p = sp.get();
        delete p;
        cout <<"Before main function exits!"<<endl;  //which I add for debug
        return 0;
}

There is no error in compiling. But an Error goes like below when running

***Error in './ex12_13': double free or corruption(out): 0x09b97018***

And the context to debug Before main function exits! has not been excuted, which means the error happens just after delete operation in my opinion. I also use 'gdb' the debug this program and error pops out just after delete indeed.

SO, how to explain the error? Delete freed the memory already but when does the second free happen? Before main function exits?


I changed the initialization of sp from make_shared function to new and use my own deleter function in place of delete.

        #include<iostream>
        #include<memory>
        using namespace std;
        int main(){
        auto deleter = [](int*p){
             cout<<"deleter called"<<endl; delete p;
        };
        shared_ptr<int> sp(new int, deleter);
        auto p = sp.get();
        delete p;
        cout <<"Before main function exits!"<<endl;  //which I add for debug
        return 0;
}

Then the output turns out to be

Before main function exits!
deleter called
***Error in './ex12_13_2': double free or corruption(out): 0x08995998***

when the program goes out of main scope, the local variable shared_ptr p will be destroyed and the memory p points to will be deleted by calling deleter.

That's why the ”before main function exits!" shows firstly, the deleter called shows later and finally the double free error.

So I think the confusion I put forward above is mainly from make_shared. @Ben Voigt gives a detailed explanation.

You are deleting a pointer that didn't come from new, so you have undefined behavior (anything at all can happen).

But the underlying reason maybe could only be found from the implement of make_shared.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
周炎兵
  • 21
  • 3
  • 1
    I got another error here -- http://ideone.com/eMJMOJ – Diego May 18 '15 at 03:31
  • @Diego The error you mentioned does not occur on my g++ compiler and it also doesn't occur on this online complier [link]http://coliru.stacked-crooked.com/ – 周炎兵 May 18 '15 at 05:05

1 Answers1

4

when is the second free happens before main function exits?

Actually, it doesn't. Now, it is entirely possible that your program DOES crash on the delete p;, but not because of a double free. You are deleting a pointer that didn't come from new, so you have undefined behavior (anything at all can happen). In particular, make_shared is often optimized to minimize allocations by placing the metadata (with the reference count and deleter) and the object in a single allocation. That allocation could be made using new[], or the resulting object pointer could be in the middle, not the beginning, of the allocation. In either case, trying to delete the object directly (even if releasing the smart pointer to avoid a future second deallocation) will be nothing but trouble.

However, we can't be sure exactly where it is crashing, because your test code has a small flaw.

cout <<"Before main function exits!"<<endl;

does not display text immediately, it just adds it to the stdout buffer. Because the program crashes, the buffer is never actually written to the associated file descriptor.

For "printf debugging", always use an unbuffered stream such as cerr

cerr << "Before main function exits!" << endl;

then you will see the true order of events.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • 6
    [`Inserts a new-line character and flushes the stream.`](http://www.cplusplus.com/reference/ostream/endl/) – Diego May 18 '15 at 03:29
  • 2
    The `flush` manipulator calls `flush()` on the stream. `endl` does that too (after inserting a newline character). – Benjamin Lindley May 18 '15 at 03:29
  • @BenjaminLindley: Maybe buffering outside the iostreams layer, then? IDEs probably use pipes to capture the output, and that could be buffered also? In any case, using `stderr` instead of `stdout` avoids any buffering problems. – Ben Voigt May 18 '15 at 03:35
  • @BenjaminLindley: I just made the change, but nothing has changed when executing. – 周炎兵 May 18 '15 at 03:35
  • I'm pretty sure your last paragraph is the answer, and should be brought to the top, instead of being an afterthought. – Benjamin Lindley May 18 '15 at 03:40
  • Nice observation about there being no call to new for the int stored by the shared pointer. – Martin York May 18 '15 at 03:47
  • One thing to try (and it works for me, i.e. the output shows up, even without a forced flush) is to use the raw pointer constructor for `shared_ptr`, instead of `make_shared`. e.g. `std::shared_ptr sp(new int);` – Benjamin Lindley May 18 '15 at 03:48
  • @BenjaminLindley Good advice. The results changed and I will update the results later. – 周炎兵 May 18 '15 at 03:55
  • @BenVoigt Thanks a lot for your comprehensive view – 周炎兵 May 18 '15 at 03:56