0

i am making a program and decided to make my own exceptions so i wrote the following header-only file:

#ifndef ARGUMENT_EXCEPTIONS
#define ARGUMENT_EXCEPTIONS

#include <exception>


namespace AAerr {

    class ArgumentException : public std::exception {
    private:
        const char* msg;
        static constexpr char* funcName = (char*)"ArgumentException";
    public:
        ArgumentException(const char* msg_) {
            msg = msg_;
        }

        const char* getMessage() {
            return msg;
        }

        virtual const char* what() const throw() {
            return funcName;
        }
    };


    class WrongReturnType : public ArgumentException {
    private:
        const char* msg = "Wrong Type";
        char requestedType;
        char ofType;
        static constexpr char* funcName = (char*)"WrongReturnType";
    public:
        WrongReturnType(const char requested, const char is) : ArgumentException(msg) {
            requestedType = requested;
            ofType = is;
        }


        char get_requested_type() {
            return requestedType;
        }


        char get_of_type() {
            return ofType;
        }

        virtual const char* what() {
            return funcName;
        }
    };

}

#endif // ARGUMENT_EXCEPTIONS

and when i tried to throw and catch one of them in my program it never caught anything:

#include "exception_header_file.hpp" // the name of the header file
#include <iostream>

int main() {
    try {
        throw AAerr::ArgumentException("TEST");
    } catch (AAerr::ArgumentException& exc) {
        std::cout << "CAUGHT EXCEPTION" << std::endl; // never executed
    }
}

and then i made a second file (just to figure out where the problem is):

#include <iostream>

#include <exception>

namespace AAerr {

    class Exc : public std::exception {
        private:
            const char* msg;
            static constexpr char* funcName = (char*)"TEST FUNC";
        public:
            Exc(const char* msg_) {
                msg = msg_;
            }

            const char* getMessage() {
                return msg;
            }

            virtual const char* what() {
                return funcName;
            }
    };

    class Exc2 : public Exc {
        private:
            int line;
            static constexpr char* funcName = (char*)"FUNCTION";
        public:
            Exc2(const char* msg_, int line_) : Exc(msg_) {line = line_;}
            virtual const char* what() {
                return funcName;
            }
    };
};

int main() {
    try {
        throw Exc2("TEST", 5);
    } catch (AAerr::Exc& exc) {
        std::cout << "CAUGHT EXCEPTION" << std::endl; // works fine
    }
}

can someone help me find where the problem is?? i can't find any difference between these 2.

compiler: g++(gcc) platform: ubuntu(linux)

EDIT: i managed to fix the problem.

it was on the on the linker(ld).

i changed my Makefile to build the whole project instead of making and then linking everything.

what i mean is, i did:

build:
    g++ program_part1.cpp program_part2.cpp program_part3.cpp -o example.elf

instead of:

build: part1.o part2.o part3.o
    g++ part1.o part2.o part3.o -o output.elf

part1.o: program_part1.cpp program_part1.hpp
    g++ -c program_part1.cpp -o part1.o

...
...
  • 1
    Not reproducible: http://coliru.stacked-crooked.com/a/a9ee8ea92b734574 – user1810087 Jun 07 '21 at 14:46
  • It is safer not to use header only classes for things which are using RTTI (catching exception is using that). Problem can manifest when dynamic libraries are used (your question do not describe that). – Marek R Jun 07 '21 at 14:47
  • Your code works as expected, although you use member variable `msg` before it is initialized. https://godbolt.org/z/T8xqqqcsz – Drew Dormann Jun 07 '21 at 14:49
  • Not sure if this would cause problems but: Is `msg = msg_;` correct for initializing a string member variable? And it looks like `ArgumentException` and `WrongReturnType` actually have different signatures on their `what` methods, and I'm not sure how deliberate that is. – Nathan Pierson Jun 07 '21 at 14:55

2 Answers2

0

I suspect that problem is in "main program", see OP comment in other answer:

yeah i tried and it's the same thing. it doesn't work on my main program, but works fine on the testing program i have – user898238409

If "main program" is using dynamic libraries and exception are defined as "header only", this can lead to situation that RTTI (Run Time Type Information) is generated for this class multiple times. One for each include for dynamic library and main executable where this header file is included.

For example this can go like this:

  1. dynamic library creates instance of class AAerr::ArgumentException using RTTI generated for that library when exception and throws this as exception.
  2. main executable is trying catch that exception using RTTI which was build for that executable.

Since those two RTTI do not match to each other catch statement can't notice that expected exception is thrown.

Proper fix for that is to drop "header only" exceptions so all virtual methods should be defined in cpp file. This will lead to well defined association with specific library. As a result only one RTTI will be present for ArgumentException and WrongReturnType.

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • so you mean i need to make the exceptions like a normal program(a .hpp and .cpp files)? – user898238409 Jun 07 '21 at 15:05
  • First clarify that you have dynamic libraries (possibly edit your question). If yes then "yes". Basically you have to force linker to generate only one RTTI for those classes. – Marek R Jun 07 '21 at 15:06
  • If not try this one: https://stackoverflow.com/a/38901400/1387438 – Marek R Jun 07 '21 at 15:10
-2

Have you tried catching std::exception instead of the exception class?

Like this:

try{
throw AAerr::Argument exception("Test");
} catch (std::exception exc) {
std::cout << "HEY" << std::endl;
}
PTorPro
  • 63
  • 8