non-portable way to find exception type in catch (...) for g++ - exception

Related questions:
Determining exception type after the exception is caught?
How can I determine the current exception in a catch (...) block?
This question differs because I don't care about portability. I'm interested in code specifically for g++ or perhaps even specific versions of g++ (4.6.3). It will not be used in production.
I'm dealing with legacy code that has thousands of throw statements with perhaps hundreds of thrown types. This code runs on nearly 1000 machines and catches about 40 throws per day. It is not repeatable.
At the outside layer, I can do a try { /.../ } catch (...) { /* caught it */ } and see that an exception was thrown. But I have not been able to find the type of the exception, let alone the location it is thrown from.
I believe the information must be available because code like the following works and prints "Y":
#include <iostream>
using namespace std;
struct X {};
struct Y {};
struct Z {};
int main(int, char **) {
try {
//...
throw Y();
//...
} catch (...) {
cout << "Caught unknown" << endl;
try {
throw;
} catch (const X &x) {
cout << "X" << endl;
} catch (const Y &y) {
cout << "Y" << endl;
} catch (const Z &z) {
cout << "Z" << endl;
}
}
}
Are there any [non-portable|dirty|nasty|ugly]* tricks to identify the exception type under g++ in a catch (...)?

Here's what I use:
#include <cxxabi.h>
using std::string;
string deMangle(const char* const name)
{
int status = -1;
char* const dem = __cxxabiv1::__cxa_demangle(name, 0, 0, &status);
const string ret = status == 0 ? dem : name;
if (status == 0)
free(dem);
return ret;
}
string getGenericExceptionInfo()
{
const std::type_info* t = __cxxabiv1::__cxa_current_exception_type();
char const* name = t->name();
return deMangle(name);
}
Usage:
catch (...)
{
std::cerr << "caught: " << getGenericExceptionInfo() << std::endl;
}

Related

How can i check if the user inputs only 0-9 digits?

When the user enters a character it's converted into a integer.
I need the ibans array with only 0-9 digits.
How can i use try-catch?
Can i use more formal functions?
I tried and it didn't work:
int* create_iban() throw(){
int* ibans = new int[16]{};
int i=0;
cout << "Digit your custom IBAN: ";
do{
cin>>ibans[i];
if(!(isdigit(ibans[i])))
throw "No digit entered!";
i++;
} while(i<16);
return ibans;
}
int main(){
try{
create_iban();
} catch(const char* ex){
cout << ex << endl;
}
}

How can I get my queue in C++ work? Unhandeled Exception: Access violation reading location

I got a problem by implementing a queue in C++. I looked for similar problems, but didn't find anything usefull.
I'm using Visual Studio 2019.
I seperated my program in a Main.cpp, a Queue.h and Queue.cpp, Patient.h and Patient.cpp.
I tried to convert the concept for this from Java to C++, but I just can't find a solution for my function getInfo().
I get an exception like this:
Unhandled exception at 0x7C0EF3BE (ucrtbased.dll) in Queue.exe: 0xC0000005: Access violation reading location 0xE8884D8D.
Would be nice if anyone could help me with my problem and explain what I did wrong.
I'm just a beginner so don't be too harsh on me pls xD
Main.cpp:
#include "Queue.h"
#include "Patient.h"
int main() {
Queue queue;
Patient patient1("Name1");
Patient patient2("Name2");
queue.add(patient1);
queue.add(patient2);
queue.getInfo();
}
Queue.h:
#pragma once
#include <iostream>
#include "Patient.h"
using namespace std;
class Queue {
private:
Patient* beginning;
Patient* end;
int amount;
public:
Queue();
void add(Patient p);
Patient remove();
void getInfo();
};
Queue.cpp:
#include "Queue.h"
Queue::Queue() {
beginning = 0;
end = 0;
amount = 0;
}
void Queue::add(Patient p) {
if (amount == 0) {
beginning = &p;
end = &p;
} else {
end->setFollower(p);
end = &p;
}
amount++;
}
Patient Queue::remove() {
if (amount == 0) {
cout << "You can't remove a patient. The Queue is empty!" << endl;
} else {
*beginning = beginning->getFollower();
amount--;
}
return *beginning;
}
void Queue::getInfo() {
if (amount == 0) {
cout << "The Queue is empty!" << endl;
} else {
cout << "There are " << amount << " Patients in the Queue!" << endl;
cout << "The following list provides all Patients in the Queue-order:" << endl;
beginning->getInfo();
}
}
Patient.h:
#pragma once
#include <iostream>
#include <string>
using namespace std;
class Patient {
private:
string name;
Patient* follower;
string* nameptr;
public:
Patient(string newname);
void setFollower(Patient p);
Patient getFollower();
void getInfo();
};
Patient.cpp:
#include "Patient.h"
Patient::Patient(string newname) {
name = newname;
follower = 0;
nameptr = &name;
}
void Patient::setFollower(Patient p) {
follower = &p;
}
Patient Patient::getFollower() {
return *follower;
}
void Patient::getInfo() {
cout << *nameptr << endl;
if (follower == 0) {
cout << "No follower existing!" << endl;
}
else {
follower->getInfo();
}
cin.get();
}
There are a few places where you mix up passing by value with passing by reference.
To start with, the first problem is here:
void Queue::add(Patient p) {
if (amount == 0) {
beginning = &p;
end = &p;
} else {
end->setFollower(p);
end = &p;
}
amount++;
}
You are passing the value of Patient p rather than a reference to the actual object. To fix this you only need to add an "&" to your functional call like this:
void Queue::add(Patient& p) {
if (amount == 0) {
beginning = &p;
end = &p;
} else {
end->setFollower(p);
end = &p;
}
amount++;
}
Note the "&" in the parameters list. Then you must also update the function header:
class Queue {
private:
Patient* beginning;
Patient* end;
int amount;
public:
Queue();
void add(Patient& p);
Patient remove();
void getInfo();
};
You must also pass by reference for your setFollower function:
void Patient::setFollower(Patient& p) {
follower = &p;
}
and in the header file:
void setFollower(Patient& p);
What you need to know going forward is that in C++ all arguments are passed by value unless you specify passing by reference in the function's parameter list. Here is an article about passing variables to functions if you'd like to read more (https://iq.opengenus.org/call-by-value-vs-call-by-reference-cpp/).

Dynamic function call through member function via map and arguments unpacking through template

I have tried code written on some link provided for dynamic function call , but unable to run code on machine .I tried to run code present at stackoverflow.com/questions/15764078/dynamically-creating-a-c-function-argument-list-at-runtime through member function.
It is is giving bad call exception while running :
Code snnippets
#include <iostream>
#include <functional>
#include <stdexcept>
#include <string>
#include <boost/any.hpp>
class Test;
class Test
{
public:
template <typename Ret, typename... Args>
Ret callfunc (std::function<Ret(Args...)> func, std::vector<boost::any> anyargs);
template <typename Ret>
Ret callfunc (std::function<Ret()> func, std::vector<boost::any> anyargs)
{
if (anyargs.size() > 0)
throw std::runtime_error("oops, argument list too long");
return func();
}
template <typename Ret, typename Arg0, typename... Args>
Ret callfunc (std::function<Ret(Arg0, Args...)> func, std::vector<boost::any>anyargs){
if (anyargs.size() == 0)
throw std::runtime_error("oops, argument list too short");
Arg0 arg0 = boost::any_cast<Arg0>(anyargs[0]);
anyargs.erase(anyargs.begin());
std::function<Ret(Args... args)> lambda =
([=](Args... args) -> Ret {
return func(arg0, args...);
});
return callfunc (lambda, anyargs);
}
template <typename Ret, typename... Args>
std::function<boost::any(std::vector<boost::any>)> adaptfunc (Ret (Test::*func)(Args...)) {
std::function<Ret(Test*,Args...)> stdfunc = func;
std::function<boost::any(std::vector<boost::any>)> result =
([=](std::vector<boost::any> anyargs) -> boost::any {
return boost::any(callfunc(stdfunc, anyargs));
});
return result;
}
int func1 (int a)
{
std::cout << "func1(" << a << ") = ";
return 33;
}
};
int main ()
{
Test a;
std::vector<std::function<boost::any(std::vector<boost::any>)>> fcs =
{
a.adaptfunc(&Test::func1)};
std::vector<std::vector<boost::any>> args =
{{777}};
// correct calls will succeed
for (int i = 0; i < fcs.size(); ++i)
std::cout << boost::any_cast<int>(fcs[i](args[i])) << std::endl;
return 0;
}
This code compiled successfully
But it failed to run and crashed
In main function for loop.
Function needs typecast according to their signature e.g.:
a.adaptfunc((int(*)(int))&Test::func1)};
After this typecast function call will not fail

C++ - Exception handling

I'm learning exception handling in C++. Here is my code:
#include <iostream>
#include <cmath>
using namespace std;
class point{
private:
float x, y;
public:
enum Error{
negative_coordinates,
};
point();
point(float, float);
~point();
float return_x();
float return_y();
};
point::point(){
}
point::point(float a, float b){
if(x < 0 && y < 0){
throw negative_coordinates;
}
else{
x = a;
y = b;
}
}
point::~point(){
}
float point::return_x(){
return x;
}
float point::return_y(){
return y;
}
int main()
{
try{
float x, y;
cout << "Enter coordinates of some point: " << endl;
cin >> x >> y;
if(x < 0 && y < 0){
throw (0);
}
}
catch(point::Error e){
const char * message [] = {"You entered negative coordinates"};
cout << "" << message[e] << endl;
}
}
If I put two negative values I got this:
terminate called after throwing an instance of 'int'
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
Process returned 3 (0x3) execution time : 5.420 s
Press any key to continue.
Any idea?
You throw an 'int' when you enter two negative values, but you catch a point. The types of your throw and catch need to be the same. If I change: catch(point::Error e) to catch(int e), the program runs fine.
As per: http://www.cplusplus.com/doc/tutorial/exceptions/

private C++ template function in a regular class - OpenCL

I am trying to create a customized class around the OpenCL C++ wrapper to get some specific information from the available devices. For example get the number of available GPUs, CPUs, etc. in a platform. To reduce code I decided to implement a private template function as shown below:
//Devices.hpp
class Devices
{
public:
Devices(const cl::Platform& inputPlatform)
{
inputPlatform.getDevices(CL_DEVICE_TYPE_ALL, &availableDevices);
}
cl_int getTotalNumberOfDevices()
{
return availableDevices.size();
}
cl_int getTotalNumberOfGPUs()
{
return countDevicesWithSpecificProperty(CL_DEVICE_TYPE, CL_DEVICE_TYPE_GPU);
}
private:
std::vector<cl::Device> availableDevices;
template <typename T>
cl_int countDevicesWithSpecificProperty(
const cl_device_info& deviceInfo,
const T& searchPropertyValue)
{
cl_int totalNumberOfDevices = getTotalNumberOfDevices();
T response;
cl_int count = 0;
for (cl_int i = 0; i < totalNumberOfDevices; ++i)
{
try
{
availableDevices.at(i).getInfo(deviceInfo, &response);
}
catch (cl::Error e)
{
return e.err();
}
if (response == searchPropertyValue) ++count;
}
return count;
}
};
While the code compiles correctly, getInfo throws a CL_INVALID_VALUE error. When I implemented the same code using regular function (instead of a template) the code works fine:
//Devices.hpp
class Devices
{
public:
Devices(const cl::Platform& inputPlatform)
{
inputPlatform.getDevices(CL_DEVICE_TYPE_ALL, &availableDevices);
}
cl_int getTotalNumberOfDevices()
{
return availableDevices.size();
}
cl_int getTotalNumberOfGPUs()
{
return countDevicesWithSpecificProperty(CL_DEVICE_TYPE, CL_DEVICE_TYPE_GPU);
}
private:
std::vector<cl::Device> availableDevices;
cl_int countDevicesWithSpecificProperty
(const cl_device_info& deviceInfo,
const cl_device_type& searchPropertyValue)
{
cl_int totalNumberOfDevices = getTotalNumberOfDevices();
cl_device_type response;
cl_int count = 0;
for (cl_int i = 0; i < totalNumberOfDevices; ++i)
{
try
{
availableDevices.at(i).getInfo(deviceInfo, &response);
}
catch (cl::Error e)
{
return e.err();
}
if (response == searchPropertyValue) ++count;
}
return count;
}
};
Any thoughts?
PS: The method is invoked as follows:
//main.cpp
#define __CL_ENABLE_EXCEPTIONS
#include <iostream>
#include <vector>
#include <CL/cl.hpp>
#include "Devices.hpp"
int main()
{
try
{
std::vector<cl::Platform> availablePlatforms;
cl::Platform::get(&availablePlatforms);
Devices d(availablePlatforms[0]);
std::cout << d.getTotalNumberOfGPUs() << std::endl;
}
catch (cl::Error e)
{
std::cout << e.what() << std::endl << e.err() << std::endl;
}
return 0;
}
The issue is that your response variable doesn't have the correct type in your templated version. This is because you are passing CL_DEVICE_TYPE_GPU to the templated parameter, which is a preprocessor macro, and so won't necessarily have the correct type needed for the device info query.
One solution is to explicitly cast the templated parameter to ensure it has the correct type:
return countDevicesWithSpecificProperty(CL_DEVICE_TYPE, (cl_device_type)CL_DEVICE_TYPE_GPU);
Check assembler listing for both cases. There should be some difference in what compiler generates.