According to a knowledgeable author within the C++ community, the code shown below should not compile. Is he wrong?
Asked Answered
P

3

1

According to Herb Sutter the code below wouldn't compile. See this site http://www.gotw.ca/gotw/066.htm from where I've extracted the following text, regarding function-try-blocks :

Toward Some Morals

Incidentally, this also means that the only (repeat only) possible use for a constructor function-try-block is to translate an exception thrown from a base or member subobject. That's Moral #1. Next, Moral #2 says that destructor function-try-blocks are entirely usele--

"--But wait!" I hear someone interrupting from the middle of the room. "I don't agree with Moral #1. I can think of another possible use for constructor function-try-blocks, namely to free resources allocated in the initializer list or in the constructor body!"

Sorry, nope. After all, remember that once you get into your constructor try-block's handler, any local variables in the constructor body are also already out of scope, and you are guaranteed that no base subobjects or member objects exist any more, period. You can't even refer to their names. Either the parts of your object were never constructed, or those that were constructed have already been destroyed. So you can't be cleaning up anything that relies on referring to a base or member of the class (and anyway, that's what the base and member destructors are for, right?).

Assuming this quote, the following code should not compile, as the object cat has already been destructed by the time the process runs into the catch clause. But it does, at least with VSC2008.

class Cat
{
    public:
    Cat() { cout << "Cat()" << endl; }
    ~Cat() { cout << "~Cat()" << endl; }
};

class Dog
{
    public:
    Dog() { cout << "Dog()" << endl; throw 1; }
    ~Dog() { cout << "~Dog()" << endl; }
};


class UseResources
{
    class Cat *cat;
    class Dog dog;

    public:
    UseResources();
    ~UseResources() { delete cat; cat = NULL; cout << "~UseResources()" << endl; }
};

UseResources::UseResources() try : cat(new Cat), dog() { cout << "UseResources()" << endl; } catch(...)
{
    delete cat;
    throw;
}
Paneling answered 3/12, 2011 at 11:55 Comment(0)
T
2

I don't think Herb Sutter is actually saying that it won't compile. He is just explaining the consequences of what the standard has to say about the situation (15.3.10):

Referring to any non-static member or base class of an object in the handler for a function-try-block of a constructor or destructor for that object results in undefined behavior.

Trevelyan answered 3/12, 2011 at 12:8 Comment(0)
H
1

Assuming this quote, the following code should not compile...

Well, he didn't say they would never compile. If anything, I interpreted the quote to mean "doing this is undefined". Undefined behavior is allowed to have any result -- up to and including compiling successfully, and doing surprising things later on.

Hut answered 3/12, 2011 at 12:6 Comment(2)
Sorry, nope. After all, remember that once you get into your constructor try-block's handler, any local variables in the constructor body are also already out of scope, and you are guaranteed that no base subobjects or member objects exist any more, period. You can't even refer to their names.Paneling
Yes, and where does that say it won't compile?Hut
D
0

Compilers are different, and also there are switches that determine how much the compiler will be strict with the code it's compiling. this code will certainly cause errors (seg faults, etc). try to enable all the switches of the compiler to force it to find this.

Dichlorodifluoromethane answered 3/12, 2011 at 12:4 Comment(3)
-Wall is your friend. I believe the MSVC++ equivalent is /W4.Ascend
@Ascend With /W4 I got C4702: unreachable code referring to the Dog constructor. I didn't understand.Paneling
@Ascend The warning refers to the fact that the end of the Dog constructor is unreachable, which it's true, due to the throw 1; instruction.Paneling

© 2022 - 2024 — McMap. All rights reserved.