strange behavior in throw, catch expressions ?

when throw is used to throw object and catch gets it by reference (&) this supposes to create the object directly in the catch, i made 2 codes which somehow describe a strange behavior occurring in my visual studio express 2012, 1st code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream> 
#include <string>
using namespace std;
class A {
public:
	A(string s) {cout << "original object constructed\n";}
	A(A&) {cout << "copy object constructed\n";}
	~A() {cout << "object destructed\n";}
};
void yes() {
throw A("yes");
}
int main(void) {
	try {yes();} catch(A&a) {cout << "catch\n";}
    return 0;
}

this outputs :


original object constructed

copy object constructed

object destructed

catch

object destructed


2nd code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream> 
#include <string>
using namespace std;
class A {
public:
	A() {cout << "original object constructed\n";}
	A(A&) {cout << "copy object constructed\n";}
	~A() {cout << "object destructed\n";}
};
void yes() {
throw A();
}
int main(void) {
	try {yes();} catch(A&a) {cout << "catch\n";}
    return 0;
}

this outputs:


original object constructed

catch

object destructed


the difference between 2 codes is in the 1st constructor. the 1st code resulted in : throw creates an object, then copies it to catch, then throw deletes the original object. the 2nd code behaves normally. what does the problem seem ?
closed account (E0p9LyTq)
A proper copy constructor would be A(const A&);.

http://www.cplusplus.com/articles/y8hv0pDG/

I do believe that VS 2012 is non-standard in this respect. Neither code sample you provided would compile with TDM-GCC 4.9.2.

OTOH it could be TDM-GCC is non-standard in requiring a const qualifier in a copy constructor declaration.
Last edited on
The copy ctor should take a const reference anyway.
Likewise, your catch should be catching a const reference.

But what is happening is that the compiler is making an optimization on the second code that it fails to make on the first.

First code: you create an A1 (belongs to local stack) and throw it. Compiler creates a copy of A1 as A2 -- not on the local stack. A1 is then destructed along with the stack frame from yes(). A2 is caught.

Second code: you create an A which the compiler knows has absolutely no side effects -- it is created to be thrown -- it is created somewhere other than the local stack -- no copy ctor is needed. yes()'s local stack frame is destroyed. A is caught.

[edit]
Try this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <string>
using namespace std;

struct A
{
  string s;
  A( const string& s ): s(   s ) { cout << "string ctor\n"; }
  A( const A&      a ): s( a.s ) { cout << "copy ctor\n";   }
 ~A()                            { cout << "dtor\n";        }
};

void foo()
{
  throw A( "banana" );
}

int main()
{
  try
  {
    foo();
  }
  catch (const A& a)
  {
    cout << "caught a " << a.s << ".\n";
  }
}
string ctor
caught a banana.
dtor


Hope this helps.
Last edited on
thanks man, about 1-2 hours ago i figured out what was wrong, the new code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream> 
#include <string>
using namespace std;
class A {
public:
	A(string &s) {cout << "original object constructed\n";}
	A(A&) {cout << "copy object constructed\n";}
	~A() {cout << "object destructed\n";}
};
void yes() {
throw A(string("yes"));
}
int main(void) {
	try {yes();} catch(A&a) {cout << "catch\n";}
    return 0;
}

the & in the 1st constructor (between string and s) was missing and i amended the throw to be : throw A(string("yes"));
That's swell, but you really ought to use const references as arguments.
why is it important in this context ?
Topic archived. No new replies allowed.