C++ custom exception class I am wondering, how can I improve this simple MissingResource exception class? I am using it in my simple game.
template &lt;typename Resource&gt;
class MissingResource : public std::exception {
    std::string_view fileName{};
    std::string_view msg{};
    
public:
    MissingResource() = default;
    MissingResource(std::string_view fileName)
    : fileName{fileName}
    {
        initMsg&lt;Resource&gt;();
    }

    template &lt;typename T&gt;
    void initMsg() {
        msg = &quot;Failed loading resource: &quot;
              &quot;{ Type: &quot;    + std::string(typeid(Resource).name()) + &quot;, &quot;
              &quot;File name: &quot; + fileName.data()                      + &quot; }&quot;;
    }

    virtual const char* what() const noexcept override {
        return msg.data();
    }
};

Throw usage:
template &lt;typename Key, typename Resource&gt;
#if (__cplusplus == 202002L)
  requires Mappable&lt;Key&gt;
#endif
class ResourceHolder {
    std::unordered_map&lt;Key, std::unique_ptr&lt;Resource&gt;&gt; resources;
    std::string resourcesDir;

public:

    explicit ResourceHolder(std::string_view resourcesDir = &quot;../resources/&quot;)
            : resourcesDir{std::move(resourcesDir)}
    {}

    template &lt;typename... Args&gt;
    void insert(const Key&amp; key, std::string_view fileName, Args&amp;&amp;... args) {
        auto resPtr = std::make_unique&lt;Resource&gt;();

        bool loaded{};
        if constexpr (std::is_same&lt;Resource, sf::Music&gt;()) {
            loaded = resPtr-&gt;openFromFile(resourcesDir + fileName.data(), std::forward&lt;Args&gt;(args)...);
        } else {
            loaded = resPtr-&gt;loadFromFile(resourcesDir + fileName.data(), std::forward&lt;Args&gt;(args)...);
        }

        /** Called here */
        if (!loaded) {
            throw MissingResource&lt;Resource&gt;(fileName);
        }
        resources.emplace(key, std::move(resPtr));
}

Try-Catch usage:
ResourceManager::ResourceManager() {
    try {
        loadResources();
    } catch (const std::exception&amp; e) {
        std::cerr &lt;&lt; e.what() &lt;&lt; std::endl;
        std::exit(EXIT_FAILURE);
    }
}

         

Exemplary error message:
what():  Failed loading resource: { Type: N2sf11SoundBufferE, File name: Death.wav }

P.S: If you see some smelly code or have doubts or found any kind of other mistakes, I would be looking forward to knowing them. Thanks!
std::string_view
Firstly, there seems to be some misusages of string_view. string_view is non-owning, and is a view to an allocated char array (such as string).
The usage
template &lt;typename Resource&gt;
class MissingResource : public std::exception {
    std::string_view fileName{};
    std::string_view msg{};
    
public:
    [...]
    template &lt;typename T&gt;
    void initMsg() {
        msg = &quot;Failed loading resource: &quot;
              &quot;{ Type: &quot;    + std::string(typeid(Resource).name()) + &quot;, &quot;
              &quot;File name: &quot; + fileName.data()                      + &quot; }&quot;;
    }
    [...]
};

Is dangerous, since after calling initMsg(), msg will point to an destroyed object (the right hand string is temporary).
Better change it to be an owning string in this case: std::string_view msg =&gt; std::string msg. I assume you already have it like this, otherwise it would provide the output which you gave in the description.
Secondly, the other member variable std::string_view fileName does not seem necessary. Since you create the error message for msg with fileName and do not use alone, we can skip it, right?
General design of MissingResource
Applying the changes above, we have:
template &lt;typename Resource&gt;
class MissingResource : public std::exception {
    std::string msg{};
    
public:
    MissingResource() = default;
    MissingResource(std::string_view fileName)
    {
        initMsg&lt;Resource&gt;();
    }

    template &lt;typename T&gt;
    void initMsg(std::string_view fileName) {
        msg = &quot;Failed loading resource: &quot;
              &quot;{ Type: &quot;    + std::string(typeid(Resource).name()) + &quot;, &quot;
              &quot;File name: &quot; + fileName.data()                      + &quot; }&quot;;
    }

    virtual const char* what() const noexcept override {
        return msg.data();
    }
};

initMsg is currently a public method, but from what I see, it's only used locally in the constructor. If this is the case, it should rather be a private method - you want to keep the public API for the class as simple and small as possible.
Another improvement would be to be able to create msg in the constructor list - so that it does not have to be created twice. We can do this by making the initMsg a static method.
Let's remove the extra unnecessary template for initMsg as well - the entire class already holds the template argument.
And note that virtual + override is unnecessary. If you mark a method as overrided, it is implicitly virtual. Remove virtual for unnecessary noise.
We now have something like this:
template &lt;typename Resource&gt;
class MissingResource : public std::exception {
    std::string msg{};

    static std::string initMsg(std::string_view fileName) {
        return &quot;Failed loading resource: &quot;
              &quot;{ Type: &quot;    + std::string(typeid(Resource).name()) + &quot;, &quot;
              &quot;File name: &quot; + fileName.data()                      + &quot; }&quot;;
    }
    
public:
    MissingResource() = default;
    MissingResource(std::string_view fileName) : msg{initMsg&lt;Resource&gt;()}
    {}

    const char* what() const noexcept override {
        return msg.data();
    }
};

ResourceHolder
Since this review is already long, I will just point out one thing in ResourceHolder, namely in insert. We can avoid separating declaration from initialization for bool loaded (and make it const!) by encapsulating the logic into a separate method. This might be a bit preferential, but it is good practice to avoid separating declaration and initialization.
Something like this:
private:
    bool fromFile(std::string_view fileName, Args&amp;&amp;... args) 
    {
    if constexpr (std::is_same&lt;Resource, sf::Music&gt;()) {
            return resPtr-&gt;openFromFile(resourcesDir + fileName.data(), std::forward&lt;Args&gt;(args)...);
        } 
    else {
            return resPtr-&gt;loadFromFile(resourcesDir + fileName.data(), std::forward&lt;Args&gt;(args)...);
    }

public:
    template &lt;typename... Args&gt;
    void insert(const Key&amp; key, std::string_view fileName, Args&amp;&amp;... args) {
        auto resPtr = std::make_unique&lt;Resource&gt;();
    
        const bool loaded = fromFile(fileName, std::forward&lt;Args&gt;(args)...)
        
        /** Called here */
        if (!loaded) {
            throw MissingResource&lt;Resource&gt;(fileName);
        }
        resources.emplace(key, std::move(resPtr));
    }