17

I have set up a library providing an exception class derived from the standard exception:

#include <stdexcept>
#include <string>

class BaseException : public std::runtime_error
{
    public:
        BaseException( std::string const & msg );
};

So far, so good. Compiles and handles quite well on Unix. Now I am prepping this for compilation into a Windows DLL:

#ifdef WIN32
#define MY_EXPORT __declspec(dllexport)
#else
#define MY_EXPORT
#endif

#include <stdexcept>
#include <string>

class MY_EXPORT BaseException : public std::runtime_error
{
    public:
        BaseException( std::string const & msg );
};

However, this gives me warning C4275: non – DLL-interface class 'std::runtime_error' used as base for DLL-interface class 'BaseException'.

And unfortunately, I am somewhat allergic to Microsoft-style documentation: Excessively wordy, and not very to the point. It keeps leaving me utterly confused as to what is actually expected of me to solve my problem.

Can any of you enlighten me? I could just drop the base class, but then catching std::runtime_error or std::exception would not catch my custom exception class, and I would very much prefer this to be possible. So...?

DevSolar
  • 67,862
  • 21
  • 134
  • 209

1 Answers1

17

There are a few options for you in this type of situation.

  1. Export it.
  2. Ignore it.
  3. In-line it.

It is important to bear in mind that the "correct" way to export class from a dll is to export the entire class, including bases and members. For this reason there are several techniques such as this one on CodeProject, that use an "interface" and appropriate factory to create the class (and matching destruction).

This is not too useful for you in this situation, trying to export std::runtime_error is probably more effort and likely to introduce even bigger issues later on.

Taken from the Microsoft Connect site here (webarchive), the family of these errors are essentially noise;

I recommend avoiding this in the first place - putting STL types in your DLL's interface forces you to play by the STL's rules (specifically, you can't mix different major versions of VC, and your IDL settings must match). However, there is a workaround. C4251 is essentially noise and can be silenced...

Stephan T. Lavavej (one of the maintainer's of Micrsoft's C++ library).

So long as the compiler options are consistent through the project, just silencing this warning should be just fine.

The final option is to define the BaseException class inline and not export it at all.

In my experience, the inline option landed up almost always being the easiest for exception classes.


Changes in the C++ runtime for VS2015, have resulted in changes to the exporting of std::exception (It is not exported from the runtime).

The inline option now seems to be the most appropriate at this time (your mileage may vary).

class Exception : exception {
public:
    char const* what() const override;
};

inline char const* Exception::what() const {
    /*...*/
};
Niall
  • 30,036
  • 10
  • 99
  • 142
  • So if I define `BaseException` inline, I don't have to `dllexport` it, and the client code can still catch an exception of that type thrown by DLL code? – DevSolar Jul 01 '14 at 14:10
  • 1
    @DevSolar Pretty much, just be aware to not change compiler options and defines related to the standard library (iterator debugging etc.) and you should be fine. – Niall Jul 01 '14 at 14:11
  • I understand the caveat, but in my case the client environment is very well-defined (the Windows version is custom-built for a specific client anyway), so that's fine. Thank you, also for the good link! – DevSolar Jul 01 '14 at 14:14
  • @DevSolar As an aside, where I have exported an exception class, it's been derived from `std::exception` and that is, IIRC, already exported out from the MSVC runtime library. – Niall Jul 01 '14 at 14:33
  • 1
    And indeed it is, while `std::runtime_error` is not. Yay Microsoft for screwing this one up. (I much prefer to derive off `std::runtime_error` because of the `char const *` constructor, which `std::exception` is missing and which is making things *so much* easier. I know why I prefer to avoid coding on Windows...) – DevSolar Jul 01 '14 at 15:12
  • If required, you still can export particular methods of the `BaseException` class. – Dmytro Ovdiienko Jul 23 '15 at 08:31
  • @DevSolar. FWIW, VS2015 seems to no longer have `std::exception` being export from the runtime. I'm know left refactoring some code w.r.t. the exporting of exceptions. – Niall Jul 28 '15 at 14:24
  • 1
    The microsoft connect link leads to a login page and not something useful. – Sqeaky Feb 16 '16 at 18:22
  • 1
    @sqeaky. I'll try find a public visible version, if you have a live.com or outlook.com etc. account, you can use that. The key bit is the quoted part in the answer thought. Do not the comment above on the changes in VS2015. – Niall Feb 16 '16 at 18:41
  • 1
    @Sqeaky. Looks like the original issue has been removed, it was for VS2010, so I'm not that surprised. I've found a webarchive link and added that as well. – Niall Mar 01 '16 at 07:37
  • @Niall - Can you please provide an example of an inline class on Microsoft platforms? Searching results in a lot of noise for inline member functions. If you are just saying replace `declspec(dllexport)` with `inline`, then the example would be most welcomed because I am encountering compile errors. – jww Jan 07 '19 at 20:19
  • @jww it’s the usual inline if the methods, either as part of the class definition or inline outside it. What compiler errors do you have? – Niall Jan 07 '19 at 20:33
  • VS 2017 compiler. I changed a particular declaration to `class inline Exception : public std::exception` (from `declspec(dllexport)`). Code I am experimenting with is [here](https://github.com/weidai11/cryptopp/blob/master/cryptlib.h#L158). The inline declaration on a class looks unusual to me. A typical error is *`error C2332: 'class': missing tag name`*. (We still don't have a Windows DLL because of the problems associated with trying to create one. I'm trying to remedy that now). – jww Jan 07 '19 at 20:41
  • I get a similar error with `class declspec(inline) Exception : public std::exception`. Error is *`error C2059: syntax error: 'inline'`*. – jww Jan 07 '19 at 20:44
  • @jww. There isn’t anything to add to the `class`, it should be inline on the methods `class Exception : exception { public: inline char const* what()... };` – Niall Jan 08 '19 at 05:17