Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where is the thrown object in c++?

Tags:

c++

exception

I want to figure out where my thrown object is stored in memory. So I wrote a tiny program for it:

#include <iostream>

#define print_dist() int a;\
    do { std::cout << __FUNCTION__ << "() a[" << (long)&a - (long)ptrMainStackBase << "]" << std::endl; } while (0)

#define print_distx(x) \
    do { std::cout << __FUNCTION__ << "() " #x "[" << (long)&x - (long)ptrMainStackBase << "]" << std::endl; } while (0)

#define print_distxy(x, y) \
    do { std::cout << __FUNCTION__ << "() " #x "(ex)[" << (long)&x - (long)y << "]" << std::endl; } while (0)

class CTest
{
    public:
        CTest()
        { std::cout << "CTest::CTest" << std::endl; }

//    private:
        CTest(const CTest&)
        { std::cout << "copy" << std::endl; }
};
const CTest *ptrException;
int *ptrMainStackBase;

void Test2()
{
    print_dist();
    CTest test;
    print_distx(test);
    std::cout << "&test=" << &test << std::endl;
    throw test;
}

void Test1()
{
    print_dist();
    try
    {
        Test2();
    }
    catch (const CTest& test)
    {
        ptrException = &test;
        print_dist();
        print_distx(test);
        print_distxy(test, ptrException);
        std::cout << "&test=" << &test << std::endl;
        throw test;
    }
}

int main()
{
    int b;
    ptrMainStackBase = &b;
    print_dist();
    try
    {
        print_dist();
        Test1();
    }
    catch (const CTest& test)
    {
        print_dist();
        print_distx(test);
        print_distxy(test, ptrException);
        std::cout << "&test=" << &test << std::endl;
    }

    return 0;
}

and it prints:

main() a[-4]
main() a[-8]
Test1() a[-64]
Test2() a[-104]
CTest::CTest
Test2() test[-108]
&test=0x7fffd3b21628 <- test created here on stack
copy
Test1() a[-68]
Test1() test[-140736732956164]
Test1() test(ex)[0]
&test=0xb89090 <- and copied here
copy
main() a[-12]
main() test[-140736732956020]
main() test(ex)[144]
&test=0xb89120 <- and here

It looks like, when I throw an object, it is first copied to another stack which is far away from the normal one. Is this true? And why there are 144 byte distance between the two "exception stack frames"?

like image 513
Industrial-antidepressant Avatar asked Jul 01 '12 12:07

Industrial-antidepressant


People also ask

Which type of object is thrown by a throw statement?

The throw statement requires a single argument: a throwable object. Throwable objects are instances of any subclass of the Throwable class.

Which type of object is thrown by a throw statement C++?

The throw statement can throw various types of objects. Objects in C++ may generally be thrown by value, reference, or pointer. For example: // throw an object to be caught by value or reference throw EIntegerRange(0, 10, userValue); // throw an object to be caught by pointer throw new EIntegerRange(0, 10, userValue);

What does throw () mean in C++?

The throw keyword throws an exception when a problem is detected, which lets us create a custom error. The catch statement allows you to define a block of code to be executed, if an error occurs in the try block.

Does throw exit the function C++?

throw usually causes the function to terminate immediately, so you even if you do put any code after it (inside the same block), it won't execute. This goes for both C++ and C#.


2 Answers

When you throw an object it is indeed copied first to some temporary location. Otherwise, the stack unrolling would have taken it out of scope. Catching it then by reference would have resulted in undefined behavior, like so:

void foo() {
   A a;
   throw a;
}

void bar() {
   try {
      foo();
   } catch (A& a) {
      // use a
   }
}

Unless a had been copied to some temporary location, you'd have a reference to a variable that no longer exists in the catch. For this to work, A must have a public copy constructor (unless you're using VS, in which case it will use a private one as well...). Also, this is a good reason to catch by reference - otherwise, you'll have two copy constructions instead of one.

like image 194
eran Avatar answered Oct 12 '22 00:10

eran


It looks like, when I throw an object it is copied first to an other stack which is far away from the normal one. Is this true?

The test that was thrown does not exist when the exception is caught. That original test has already been destructed. So it has to be a copy, and new object managed separately from arguments and local variables. In other words, not on the stack.

Where it lives? That's up to the implementation. Most likely it's dynamic memory (e.g., the heap) that the implementation manages for you.

And why there are 144 byte distance between the two "exception stack frame"?

The standard doesn't say how an implementation is to treat an exception when it is re-thrown in a catch block. Since the throw of a local variable must necessarily make a copy, the easiest way to implement throw is to always make a copy.

like image 38
David Hammen Avatar answered Oct 12 '22 00:10

David Hammen