0

I wrote a few custom exceptions for my software package, all of which extend std::exception. However, when I catch thrown exceptions in my driver file, nothing is printed by e.what(). I am catching by constant reference as well. What am I missing here?

exceptions.h

#include <sstream>

struct FileNotFoundException : public std::exception
{
    const char * _func;
    const char * _file;
    int _line;
    FileNotFoundException(const char * func, const char * file, int line) : _func(func), _file(file), _line(line) {}

    const char * what() const throw()
    {
        std::stringstream stream;
        stream << "FileNotFoundException: Could not find file" << std::endl << "  In function " <<
            _func << "(" << _file << ":" << _line << ")";
        return stream.str().c_str();
    }
};

io.cpp

#include "exceptions.h"

void loadFile(const std::string &path_to_file)
{
    std::ifstream file(path_to_file.c_str());
    if (!file.is_open())
    {
        throw FileNotFoundException(__func__, __FILE__, __LINE__);
    }
    // ...
}

runner.cpp

#include "exceptions.h"
#include "io.h"

#include <iostream>


int main(int argc, char ** argv)
{
    try
    {
        loadFile("test.txt");
    }
    catch (const std::exception &e)
    {
        std::cerr << e.what() << std::endl;
        std::cerr << "Program exited with errors" << std::endl;
    }
}

OUTPUT

Program exited with errors

There is no mention of the exception's error message. How come?

marcman
  • 3,233
  • 4
  • 36
  • 71
  • Maybe an explanation of how this is a scope issue might help...? – marcman Mar 01 '17 at 12:58
  • 1
    `return stream.str().c_str();` This is UB, your stream gets destroyed when `what()` exits and therefore that pointer points to deleted memory. – Borgleader Mar 01 '17 at 12:58
  • @Borgleader: What's UB? – marcman Mar 01 '17 at 12:58
  • Undefined behavior. – Borgleader Mar 01 '17 at 12:58
  • @Borgleader: Oh ok. How might I change this to get the desired behavior then? Avoid using stringstream? – marcman Mar 01 '17 at 12:59
  • Why don't you just return a std::string? – Jahid Mar 01 '17 at 12:59
  • 3
    Don't calculate the string in the `what()` message, but store a single string with the message as a data member. Then get `what()` to return `thestring_.c_str()`. – juanchopanza Mar 01 '17 at 13:01
  • 1
    @juanchopanza: That seems to do the trick. So it was the use of `stringstream` that screws it up because the stream is closed when the function call goes out of scope and thus the stream's memory is no longer accessible. Thank you – marcman Mar 01 '17 at 13:03
  • @Jahid: Because `const char * what() ...` overloads the `std::exception` function and as such must return a C-style string. – marcman Mar 01 '17 at 13:03
  • You could extend from `std::runtime_error` or use a different name for the error function i.e a separate function. – Jahid Mar 01 '17 at 13:06

0 Answers0