Silex
Silex

Reputation: 2713

Boost shared pointer "runtime error" after it gets end of scope

I am practicing with boost and now I am testing boost shared pointers. I have a Util class which can read files. After I read the file, my "Read" method gives back a boost::shared_ptr which points to the file content. Then I pass this shared pointer to my Parser class, which parses the string line by line. After the parsing is done, then at the end of my Parser class constructor (at '}') I get a "runtime error" which points to a boost header file. More specifically to checked_delete.hpp to the "delete x" line:

template<class T> inline void checked_delete(T * x) {
   // intentionally complex - simplification causes regressions
   typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
   (void) sizeof(type_must_be_complete);
   delete x;
}

A simplifyed code looks something like this:

class File {
    string _path;
public:
    File(string path)
    ~File()
    void Open();
    boost::shared_ptr<string> Read();
    void Close();
};

class Parse {
public:
    Parse(string path) {
        File file = File(path);
        file.Open();
        boost::shared_ptr<string> fileContentPtr = file.Read();
        StartParsing(fileContentPtr);
        file.Close();
    }
    ~Parse();
    StartParsing(boost::shared_ptr<string> fileContentPtr);
};

int main() {
string path = "<some path to my file>";
Parse(path);
}

Anybody can give me a hint, what am I doing wrong? Thanks in advance!

EDIT: My Read() function:

boost::shared_ptr<string> File::Read() {
    if(file.is_open()) {
        ostringstream stream;
        stream << file.rdbuf();
        string content = stream.str();
        boost::shared_ptr<string> contentPtr(&content);
        return contentPtr;
    }
    else {
        throw std::runtime_error("File isn't opened");
    }
}

Where "file" variable is a std::fstream file which is used in Open()

Upvotes: 0

Views: 632

Answers (1)

hmjd
hmjd

Reputation: 121961

The contained object of the boost::shared_ptr must be dynamically allocated, either explicitly via new or implicitly via boost::make_shared<>. From boost::shared_ptr:

The shared_ptr class template stores a pointer to a dynamically allocated object, typically with a C++ new-expression. The object pointed to is guaranteed to be deleted when the last shared_ptr pointing to it is destroyed or reset.

In this case, the std::string instance is stack allocated and will be destructed when Read() returns:

string content = stream.str();
boost::shared_ptr<string> contentPtr(&content);

This results in the shared_ptr having a dangling pointer and an attempt to delete it when the shared_ptr goes out of scope, causing the error.

The program already has undefined behaviour as any code that attempts to access the shared_ptr after Read() is dereferencing a dangling pointer.

To correct, dynamically allocate the std::string:

return boost::make_shared<std::string>(stream.str());

Or, simpler, just return and store a std::string instance instead:

return stream.str();

as the compiler should be able to use return value optimization.


Note that c++11 introduced smart pointers, std::shared_ptr among them.

Upvotes: 5

Related Questions