Home > Blockchain >  Where to put the custom exception classes?
Where to put the custom exception classes?

Time:11-05

Suppose that I have a class which you can see below (Please read the comments too):

Foo.h

#pragma once

namespace Bar
{

class Foo
{
public:
    inline Foo( );

private:
    inline static const std::unordered_set<char> CHAR_SET {'/', '\\', '|', '-'};

    friend class Invalid_C_Exception;class
};
} // end of namespace Bar

And I have:

Foo.cpp

#include "Foo.h"

using namespace Bar;

inline Foo::Foo( )
{
}

class Invalid_C_Exception : public std::exception
{
public:
    virtual const char* what( ) const throw( )
    {
        // if implementation details are irrelevant, remove them
        std::stringstream ss;

        ss << "Invalid_C_Exception: { ";

        // compiler gives an error here because of uses of CHAR_SET
        for ( auto it = Foo::CHAR_SET.cbegin( ); it != Foo::CHAR_SET.cend( );   it )

        {
            ss << "'" << *it << "', ";
        }

        return somehow_save_the_C_string(ss.str());
    }

} Invalid_C_Exc;

1st question:

Is the existence of the global Invalid_C_Exc variable ok?

2nd question:

Why does the compiler blame me for CHAR_SET being private while trying to compile Foo.cpp. The custom exception class despite being a friend of class Foo is not able to access CHAR_SET?

3rd question:

Where should I put these custom exception classes? In separate header and source files but under the same namespace? I was undecided so I put the declaration and implementation in the source file Foo.cpp cause the exception class is designed to work for the class Foo so they're related to each other.

CodePudding user response:

There is a big difference between

friend class Invalid_C_Exception;

and

friend Invalid_C_Exception;

The latter expects that Invalid_C_Exception already exists somewhere accessible and makes that symbol a friend of Foo. The former declares a new symbol Invalid_C_Exception in the enclosing scope and makes that the new friend.

Meaning you have made Bar::Invalid_C_Exception a friend of Foo, not the global ::Invalid_C_Exception you have defined later which is still not a friend. The fact that Bar::Invalid_C_Exception will never exist is irrelevant.

Regarding your first question, Invalid_C_Exc is a global variable, by default it has external linkage. If you use it only in this translation unit(.cpp file), make it static or put it into an anonymous namespace. I would recommend not being lazy and write its definition on a separate line, it's much more clearer that way. Other than that, you can use it just fine, it is initialized before main begins and lives until the end of the program.

Regarding your third question. Wherever you want, I would generally advise for one .hpp per one exception type or tightly-grouped pack of them. Putting it into .cpp makes catching it hard.

CodePudding user response:

1st question: Is the existence of this variable ok?

Globals are not generally a great idea, and since exception objects are copied to dedicated exception storage when thrown, I don't see any use for this particular global.

second question is that why does the compiler blame me for CHAR_SET being private

You have defined a class Bar::Foo and declared its friend class Bar::Invalid_C_Exception ... but you haven't touched those at all in the implementation file. You've just declared a new and unrelated Invalid_C_Exception in the global namespace.

Remove the using namespace Bar and wrap everything below the includes in namespace Bar { ... } same as in the header. Or explicitly write Bar::Foo and Bar::Invalid_C_Exception everywhere if you prefer.

The using namespace directive makes names from the namespace visible in the enclosing scope. It doesn't suck everything added to the enclosing scope afterwards back into the namespace. How would that work if you have more than one using namespace directive? And why would using namespace std; ever be allowed?

3rd question: Where should I put these custom exception classes?

Well, you can't put the definition in your implementation file if you want anyone to be able to use it. Just put the class definition in the header, and leave only the definition of Bar::Invalid_C_Exception::what in the implementation file.

Whether they go in the same header & implementation file as the class they're friends with is up to you, it doesn't really matter.

4th question: how many questions should I ask per question?

One. It's called a question, not a questionnaire.

  • Related