0

I have the following program:

#include <string>
#include <iostream>
#include <stdexcept>
#include <sstream>


enum class Severity
{
  TRACE,
  DEBUG,
  INFO,
  WARN,
  ERROR,
  FATAL,
};

struct LogRecord
{
  const Severity          mSeverity;
  const std::string       mTimestamp;
  const char* const       mFunc;
  const size_t            mLine;
  const char* const       mFile;
  std::string             mMessage;
  std::exception          mException;   


  LogRecord& operator<<(const std::exception& e)
  {
    mException = e;
    return *this;
  }

  template <typename T>
  LogRecord& operator<<(const T& msg)
  {
    std::ostringstream ss;
    ss << msg;
    mMessage += ss.str();
    return *this;
  }
};


void throw_exception()
{
  throw std::logic_error("Logic error");
}
int main()
{
  LogRecord l{};
  try
  {
    throw_exception();
  }
  catch(std::exception& e)
  {
    l << "Test" << e;
    std::cout << l.mMessage << ": " << l.mException.what() << std::endl;
  }
}

The main function prints "Test: std::exception" instead of "Test: Logic error". The reason is that "mException = e;" does not copy the exception to the mException member of my struct. What is the reason for that and how could I archieve that "Test: Logic error" is printed?

Simon Rechermann
  • 467
  • 3
  • 18
  • Looks like you dwelled into _implementation defined_ territory :( https://en.cppreference.com/w/cpp/error/exception/operator%3D – YSC Feb 15 '23 at 16:57
  • @YSC ok I see. Do you have any suggestion for a workaround to archieve what I want to do? – Simon Rechermann Feb 15 '23 at 16:58
  • Are you maybe slicing the exception to the base type? – doctorlove Feb 15 '23 at 16:59
  • 6
    Isn't this just object slicing? – Nathan Pierson Feb 15 '23 at 16:59
  • 10
    This is just object slicing; the type thrown exception is `std::logic_error`, but it's being copied into an object of type `std::exception`, so the `std::logic_error` part gets sliced off and all that's left is the `std::exception` part. This happens any time you copy a derived object into an object whose type is one of its bases. – Pete Becker Feb 15 '23 at 16:59
  • 7
    Looks like what you really want is a [`std::exception_ptr`](https://en.cppreference.com/w/cpp/error/exception_ptr). Since `std::exception mException;` will slice. – Eljay Feb 15 '23 at 17:00
  • @Eljay but how can I use the "std::exception_ptr"? I think I can't access the what() method and I'm only able to rethrow the exception if I got it right? – Simon Rechermann Feb 15 '23 at 17:02
  • @SimonRechermann -- look at the sample code in the link that Eljay gave you. – Pete Becker Feb 15 '23 at 17:04
  • 1
    Reopened. Yes, the cause is object slicing, but that's not the end of the conversation. See the comment by @Eljay, which describes a solution to this particular problem. – Pete Becker Feb 15 '23 at 17:11
  • 2
    Would [`std::nested_exception`](https://en.cppreference.com/w/cpp/error/nested_exception) help? _"...std::nested_exception is a polymorphic mixin class which can capture and store the current exception, making it possible to __nest exceptions of arbitrary types__ within each other...."_ – Richard Critten Feb 15 '23 at 17:17
  • something like this might be what you need? https://godbolt.org/z/zhcesjdMx – Alan Birtles Feb 15 '23 at 17:22
  • 1
    @RichardCritten -- not really; `std::nested_exception` is used when an outer layer of code needs to create a new exception object with a link to an earlier exception object, so that it can throw an exception of a domain-related type when it catches a lower-level exception, without losing the original exception information. This question is just about hanging on to the original exception object, without wrapping it in another exception. `std::exception_ptr` does seem like the right answer. – Pete Becker Feb 15 '23 at 17:23
  • @AlanBirtles Thanks! Instead of `std::current_exception()` I would like to use `std::make_exception_ptr(e)` https://godbolt.org/z/a8zfzjnTT why is this not working? – Simon Rechermann Feb 15 '23 at 17:41
  • The linked duplicate is the right answer, but note that the accepted answer to that question (which insists that the only way to do this is to clone exception objects) is wrong. – Pete Becker Feb 15 '23 at 17:44
  • @SimonRechermann -- Stack Exchange is not a discussion forum. You've gotten a good answer (through the duplicate link) to your question. Now that you have a new problem, ask a new question! – Pete Becker Feb 15 '23 at 17:45
  • See the note at the bottom of https://en.cppreference.com/w/cpp/error/make_exception_ptr – Alan Birtles Feb 15 '23 at 18:48

0 Answers0