Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ throw dereferenced pointer

Tags:

c++

What is the type of the exception object in the following thrown:

Question1> range_error r("error"); throw r;

Answer1> an object of range_error

Question2> exception *p = &r; throw *p;

Answer2> a sliced object of exception

Question3> exception *p = &r; throw p;

Answer3> a pointer pointing to range_error is thrown. The capture-handling can access the range_error member functions through dynamic binding.

Do I get these question right?

// Updated and Compiled and Run on VS2010

#include <iostream>
using namespace std;

class ExClassA
{
public:
    virtual void PrintMe() const
    {
        cout << "ExClassA" << endl;
    }
};

class ExClassB : public ExClassA
{
public:
    virtual void PrintMe() const
    {
        cout << "ExClassB" << endl;
    }
};

int main(int argc, char* argv[])
{   
    ExClassB exClassB;
    ExClassA *p = &exClassB;

    try
    {
        throw *p;
    }
    catch (const ExClassA& e)
    {
        e.PrintMe();        
    }

    try
    {
        throw p;
    }
    catch (const ExClassA* e)
    {
        e->PrintMe();
    }
}

The first try-catch of above program prints "ExClassA"

The second try-catch of above program prints "ExClassB"

like image 235
q0987 Avatar asked Aug 10 '11 16:08

q0987


People also ask

Can pointers be dereferenced?

Dereferencing is used to access or manipulate data contained in memory location pointed to by a pointer. *(asterisk) is used with pointer variable when dereferencing the pointer variable, it refers to variable being pointed, so this is called dereferencing of pointers.

What happens when a pointer is dereferenced?

Dereferencing a pointer means getting the value that is stored in the memory location pointed by the pointer. The operator * is used to do this, and is called the dereferencing operator.

What is the pointer dereferencing operator?

In computer programming, a dereference operator, also known as an indirection operator, operates on a pointer variable. It returns the location value, or l-value in memory pointed to by the variable's value. In the C programming language, the deference operator is denoted with an asterisk (*).

What is the Dereferencing in C++?

Dereferencing is getting at the pointed value. Pointer variables are useful for walking the contents of a linked list data structure, using a dynamic jump table to subroutines, and passing arguments by address (so only an address is passed) rather than by value (where the entire data structure is copied).


3 Answers

Throwing an object always results in the thrown object being a copy of the object you threw, based on the static type of that object. Thus your first two answers are correct.

The third one is a little more complicated. If you catch(range_error*) you won't catch the exception because the types don't match. If you catch(exception*) you won't be able to access members of range_error in the caught pointer; you can dynamic_cast that pointer back to a range_error pointer though.

like image 185
Mark Ransom Avatar answered Oct 23 '22 01:10

Mark Ransom


I think you are right in all three. The type of the thrown object (IIRC) is the static type of the object being thrown. I would have to dig into the standard for a while to find the exact quotes, but a simple example seems to confirm this:

struct base {};
struct derived : base {};
void t() {
    derived d;
    base * b = &d;
    throw *b;
}
int main() {
    try {
        t();
    } catch ( derived const & ) {
        std::cout << "derived" << std::endl;
    } catch ( base const & ) {
        std::cout << "base" << std::endl;
    }
}

If the dynamic type of the object being thrown was used, then *b would have type derived and the first catch would succeed, but empirically the second catch is executed (g++).

In the last case, the object thrown is a pointer to exception that refers to a range_error object. The slight difference is again what can be caught, the compiler will not catch in a catch (range_error*) block. The answer is correct, but I would have specified the type of the pointer, as much as the type of the pointee. (The type of the pointer is somehow implicit in the answer)

like image 33
David Rodríguez - dribeas Avatar answered Oct 23 '22 01:10

David Rodríguez - dribeas


All three answers are correct. Just note that you'll have to catch a pointer type in the third case.

The usual way to throw an exception is:

throw range_error("error");

At the throw site, you normally know the exact type of exception you want to throw. About the only exception I can think of is when the exception was passed in as an argument, e.g.:

void f( std::exception const& whatToDoInCaseOfError )
{
    //  ...
    throw whatToDoInCaseOfError;  //  slices
}

It's not a frequence case, but if you want to support it, you'll need a separate exception hierarchy of your own, with a virtual raise function:

class MyExceptions
{
public:
    virtual ~MyExceptions() {}
    virtual void raise() const = 0;
};

template<typename ExceptionType>
class ConcreteException : public ExceptionType, public MyExceptions
{
public:
    virtual void raise() const
    {
        throw *this;
    }
};

The client code then wraps the exception he wants to be thrown in a ConcreteException, and you call the raise function on it, rather than invoke throw directly.

like image 38
James Kanze Avatar answered Oct 22 '22 23:10

James Kanze