By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,332 Members | 1,427 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,332 IT Pros & Developers. It's quick & easy.

Effective C++ by Scott Meyers

P: n/a
I right now reading this book.
And he is iterating some points I'm following since 1996, e.g.
exception safety.
But e.g. he is missing one of the major exception safety guidelines,
which is

Allocate only a single resource inside a constructor body (deallocate
in the matching destructor body).
Chain such classes into base-class/member-class relationships.
This way you are able to exploit the code generation features of the
compiler,
since you wont have to deal with partially constructed objects and
cleanup after an exception has been thrown.

I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.

Feb 23 '07 #1
Share this Question
Share on Google+
15 Replies


P: n/a
Peter wrote:
I right now reading this book.
And he is iterating some points I'm following since 1996, e.g.
exception safety.
But e.g. he is missing one of the major exception safety guidelines,
which is

Allocate only a single resource inside a constructor body (deallocate
in the matching destructor body).
Chain such classes into base-class/member-class relationships.
This way you are able to exploit the code generation features of the
compiler,
since you wont have to deal with partially constructed objects and
cleanup after an exception has been thrown.

I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.
Effective C++ is not that modern a book is it, 10 years old according to
Amazon.

Your criticism is valid I guess, but Effective C++ is a beginners book,
and exception safety is an advanced topic.

It remains an exceptionally good book, taught me more about C++ than any
other single book I've read.

john
Feb 23 '07 #2

P: n/a

Peter wrote:
I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.

and on page 138 he made a mistake in the order of constructor calls.
The correct order is:

bm1::constructor()
bm2::constructor()
Base::Base()
dm1::constructor()
dm2::constructor()
dm3::constructor()
Derived::Derived()

I left out the order of destructor calls in case of an exception.
But this is simple, as it is in reverse order.

This mistake did more damage than the book did good.

Feb 23 '07 #3

P: n/a
s5n
On Feb 23, 11:38 pm, "Peter" <pet...@xpedion.comwrote:
I right now reading this book.
And he is iterating some points I'm following since 1996, e.g.
exception safety.
But e.g. he is missing one of the major exception safety guidelines,
which is
....
I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.
Your points are valid, but don't forget how old that book is ("modern"
is not valid here, IMO). After writing that book Meyers released
Effective STL and is on the 3rd edition of More Effective C++. Not
*everything* could go into one book. :)

PS: i'm Scott Meyers' biggest fan. :)

Feb 24 '07 #4

P: n/a
On Feb 23, 6:10 pm, "Peter" <pet...@xpedion.comwrote:
Peter wrote:
I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.

and on page 138 he made a mistake in the order of constructor calls.
The correct order is:

bm1::constructor()
bm2::constructor()
Base::Base()
dm1::constructor()
dm2::constructor()
dm3::constructor()
Derived::Derived()

I left out the order of destructor calls in case of an exception.
But this is simple, as it is in reverse order.

This mistake did more damage than the book did good.

It is not in reverse order. In the sequence above Derived() is invoked
first which invokes the other constructors. The only reason
Derived::Derived() is displayed last is because that ctor body is only
executed once the member constructions are completed.
The same applies to Base counterpart. bm1 and bm2 are constructed to
completion before the Base::Base() output is executed. The fact that
bm1 and bm2 constructors were invoked implies that the Base ctor
itself was invoked first.
Feb 24 '07 #5

P: n/a

"Salt_Peter" <pj*****@yahoo.comwrote in message
news:11*********************@z35g2000cwz.googlegro ups.com...
On Feb 23, 6:10 pm, "Peter" <pet...@xpedion.comwrote:
>Peter wrote:
I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.

and on page 138 he made a mistake in the order of constructor calls.
The correct order is:

bm1::constructor()
bm2::constructor()
Base::Base()
dm1::constructor()
dm2::constructor()
dm3::constructor()
Derived::Derived()

I left out the order of destructor calls in case of an exception.
But this is simple, as it is in reverse order.

This mistake did more damage than the book did good.


It is not in reverse order. In the sequence above Derived() is invoked

the destruction is in reverse order of the constructors.
Only these destructors are called, for which the constructor was successful.
This is also true in case of the destruction is caused by an exception
thrown.
Do you claim that it is not so?

first which invokes the other constructors. The only reason
Derived::Derived() is displayed last is because that ctor body is only
executed once the member constructions are completed.
The same applies to Base counterpart. bm1 and bm2 are constructed to
completion before the Base::Base() output is executed. The fact that
bm1 and bm2 constructors were invoked implies that the Base ctor
itself was invoked first.

I'm not following.
Do you claim yet another construction order?
Do be explicit -- could you write down your construction order line by line?
But this does not matter -- I'm quite certain that I'm correct here.
I tested this in countless examples.

Feb 24 '07 #6

P: n/a
sks
"Peter" <pe****@xpedion.comwrote in message
news:11*********************@h3g2000cwc.googlegrou ps.com...
>I right now reading this book.
And he is iterating some points I'm following since 1996, e.g.
exception safety.
But e.g. he is missing one of the major exception safety guidelines,
which is

Allocate only a single resource inside a constructor body (deallocate
in the matching destructor body).
Chain such classes into base-class/member-class relationships.
This way you are able to exploit the code generation features of the
compiler,
since you wont have to deal with partially constructed objects and
cleanup after an exception has been thrown.

I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.
I didn't quite understand this but I would like to understand it. What did
you mean by "exploit the code generation features of the
compiler"?

Also, what is wrong with multiple resource allocations inside a constructor
body (as long as the matching destructor gets to deallocate them)?

Thanks.

Feb 24 '07 #7

P: n/a
* Peter:
>
"Salt_Peter" <pj*****@yahoo.comwrote in message
news:11*********************@z35g2000cwz.googlegro ups.com...
>On Feb 23, 6:10 pm, "Peter" <pet...@xpedion.comwrote:
>>Peter wrote:
I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.

and on page 138 he made a mistake in the order of constructor calls.
The correct order is:

bm1::constructor()
bm2::constructor()
Base::Base()
dm1::constructor()
dm2::constructor()
dm3::constructor()
Derived::Derived()

I left out the order of destructor calls in case of an exception.
But this is simple, as it is in reverse order.

This mistake did more damage than the book did good.


It is not in reverse order. In the sequence above Derived() is invoked


the destruction is in reverse order of the constructors.
Only these destructors are called, for which the constructor was
successful.
This is also true in case of the destruction is caused by an exception
thrown.
Do you claim that it is not so?
Peter is talking about constructor calls, you're talking about finished
initializations (constructor body executions).

Those are different things.

For example, if Base and Derived are coded like
void say( char const s[] ) { std::cout << s << std::endl; }

int theAnswer( char const s[] ) { say( s ); return 42; }

struct Base
{
Base( int ) { say( "Base constructor" ); }
};

struct Derived
{
Derived(): Base( theAnswer( "Derived init list" ) )
{ say( "Derived constructor" ); }
};

int main() { Derived(); }

But this does not matter -- I'm quite certain that I'm correct here.
I tested this in countless examples.
Try the above.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Feb 24 '07 #8

P: n/a

"sks" <sk*@yahoo.comwrote in message
news:LN*******************@newsfe14.lga...
I didn't quite understand this but I would like to understand it. What did
you mean by "exploit the code generation features of the
compiler"?

If you would have to perform an initialization of a complex object in C
you would have to perform checks if the initialization of a subobject was
successful.
In case of one initialization of some subobject fails you would have to call
the destructor of the already successful initialized subobjects.
You would have to maintain this order in the constructor and in the
destructor. Lets assume 3 parts A, B and C:
(0 return code stands for success, everything else for failure)

typedef struct
{
A sA;
B sB;
C sC;
} someStructure;

int initSomeStructure(someStructure *_p)
{ if (initA(&_p->sA))
return 1;
if (initB(&_p->sB))
{ destroyA(&_p->sA);
return 1;
}
if (initC(&_p->sC))
{ destroyB(&_p->sB);
destroyA(&_p->sA);
return 1;
}
return 0;
}
void destroySomeStructure(someStructure *_p)
{ destroyC(&_p->sC);
destroyB(&_p->sB);
destroyA(&_p->sA);
}
Usage of this code could look like this:

someStructure *p = malloc(sizeof*p);
if (!p)
{ printf("allocation of somestructure failed\n");
}
else
if (initSomeStructure(p))
{ free(p);
printf("Initialization of somestructure failed\n");

}
else
doSomething(p);

ok so far?

in C++ this would look like this:

struct SomeStructure
{ A m_sA;
B m_sB;
C m_sC;
SomeStructure(void)
{
}
};
Usage of this code would look like this:

SomeStructure *p;
try
{ p = new SomeStructure;
} catch (const std::exception &_r)
{ cout << "Initialization or allocation of somestructure failed with
msg: " << _r.why() << "\n";
}
p->doSomething();
The C++ compiler is generating all this code for you (initializaing the
subobjects and dealing with failure if initialization of some subobject
fails).
I only used a heap-allocated object to show that the compiler generates a
call to delete if the constructor fails.
Notice that you enter the same catch-block independ of whether the
constructor fails or whether new fails.

Also, what is wrong with multiple resource allocations inside a
constructor
body (as long as the matching destructor gets to deallocate them)?

if you allocate multiple resources in a single constructor-body
(
e.g. not as subobjects but e.g. pointers.
Same applies if you wrap multiple C-style resources initializations inside a
single class instead of one class for one C-style resource
):
struct A
{ B *m_pB;
C *m_pC;
D *m_pD;
A(void)
{ m_pB = createB();
try
{ m_pC = createC();
} catch (...)
{ delete m_pB;
throw;
}
try
{ m_pD = createD();
} catch (...)
{ delete m_pC;
delete m_pB;
throw;
}
}
~A(void)
{ delete m_pD;
delete m_pC;
delete m_pB:
}
};

Same applies if your creation functions are C-style error code returning
functions.
You would have to perform cleanup duty yourself.

It is better to use sub-objects:

struct A
{ std::auto_ptr<Bm_sB;
std::auto_ptr<Cm_sC;
std::auto_ptr<Dm_sD;
A(void)
: m_sB(createB()),
m_sC(createC()),
m_sD(createD())
{
}
}
Here the compiler generates the code which destroys the already successfully
constructed subobjects
if construction of some subobject fails.
And you don't need to code the destructor at all.

(
std::auto_ptr is an exception to the rule that you should undo in the
destructor what you did in the constructor.
using std::auto_ptr you undo in the destructor what you do just before
calling the constructor.
This is ok, since the constructor of std::auto_ptr never throws.
)
Using C++ Exception Handling it is finally possible to use constructors for
fallible resource allocation.
Write one class for every type of resource allocation you have to perform.
Then chain such classes into base-class or member-class relationships.
Of course you will have to know (and exploit) the order of construction of
base-objects/member-objects.

Feb 24 '07 #9

P: n/a
On Feb 23, 4:47 pm, John Harrison <john_androni...@hotmail.comwrote:
Peter wrote:
I right now reading this book.
And he is iterating some points I'm following since 1996, e.g.
exception safety.
But e.g. he is missing one of the major exception safety guidelines,
which is
Allocate only a single resource inside a constructor body (deallocate
in the matching destructor body).
Chain such classes into base-class/member-class relationships.
This way you are able to exploit the code generation features of the
compiler,
since you wont have to deal with partially constructed objects and
cleanup after an exception has been thrown.
I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.

Effective C++ is not that modern a book is it, 10 years old according to
Amazon.

Your criticism is valid I guess, but Effective C++ is a beginners book,
and exception safety is an advanced topic.

It remains an exceptionally good book, taught me more about C++ than any
other single book I've read.

john
can you suggest a good book for advanced topic in c++? e.g. the
exception safety that you mention?
Feb 24 '07 #10

P: n/a
yi*****@gmail.com wrote:
On Feb 23, 4:47 pm, John Harrison <john_androni...@hotmail.comwrote:
>>Peter wrote:
>>>I right now reading this book.
And he is iterating some points I'm following since 1996, e.g.
exception safety.
But e.g. he is missing one of the major exception safety guidelines,
which is
>>>Allocate only a single resource inside a constructor body (deallocate
in the matching destructor body).
Chain such classes into base-class/member-class relationships.
This way you are able to exploit the code generation features of the
compiler,
since you wont have to deal with partially constructed objects and
cleanup after an exception has been thrown.
>>>I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.

Effective C++ is not that modern a book is it, 10 years old according to
Amazon.

Your criticism is valid I guess, but Effective C++ is a beginners book,
and exception safety is an advanced topic.

It remains an exceptionally good book, taught me more about C++ than any
other single book I've read.

john


can you suggest a good book for advanced topic in c++? e.g. the
exception safety that you mention?

There's a series of books that grew out of the guru of the week column
(http://www.gotw.ca/gotw/), the first is called Exceptional C++ by Herb
Sutter.

Personally I didn't like the style much, but the material covered is good.

john
Feb 24 '07 #11

P: n/a
On Feb 23, 7:47 pm, John Harrison <john_androni...@hotmail.comwrote:
Peter wrote:
I right now reading this book.
And he is iterating some points I'm following since 1996, e.g.
exception safety.
But e.g. he is missing one of the major exception safety guidelines,
which is
Allocate only a single resource inside a constructor body (deallocate
in the matching destructor body).
Chain such classes into base-class/member-class relationships.
This way you are able to exploit the code generation features of the
compiler,
since you wont have to deal with partially constructed objects and
cleanup after an exception has been thrown.
I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.

Effective C++ is not that modern a book is it, 10 years old according to
Amazon.

Your criticism is valid I guess, but Effective C++ is a beginners book,
and exception safety is an advanced topic.

It remains an exceptionally good book, taught me more about C++ than any
other single book I've read.

john
I can surely say I only learned C++ properly after I read Scott
Meyers.
I agree completely with john

(and I only learned templates properly after Alexandrescu...)

Diego

Feb 26 '07 #12

P: n/a
On Feb 23, 6:10 pm, "Peter" <pet...@xpedion.comwrote:
Peter wrote:
I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.

and on page 138 he made a mistake in the order of constructor calls.
The correct order is:
<snip>
This mistake did more damage than the book did good.
Really? That seems like a slight overreaction.
Feb 26 '07 #13

P: n/a

<da***********@fastmail.fmwrote in message
news:11********************@v33g2000cwv.googlegrou ps.com...
>This mistake did more damage than the book did good.

Really? That seems like a slight overreaction.

I happen to consider the order of construction of a nontrival class
as one of the most important things to know about C++.
A lot of things can be done during construction of an object,
which somebody who does not know about this, may do inside some
init-function.
I consider usage of an init-function to be pre-C++-Exception-Handling-Style.

Feb 27 '07 #14

P: n/a
Peter wrote:
I consider usage of an init-function to be
pre-C++-Exception-Handling-Style.
A class should be easy to use, both for production clients and test cases.
So a class that has the option to construct with links to other obese
classes should also have the option to construct minimally.

Yes, adept use of fat constructors does demonstrate modern C++
understandings. That's no excuse to make every constructor fat.

--
Phlip
http://www.greencheese.us/ZeekLand <-- NOT a blog!!!
Feb 27 '07 #15

P: n/a
On Feb 24, 4:10 am, John Harrison <john_androni...@hotmail.comwrote:
ying...@gmail.com wrote:
On Feb 23, 4:47 pm, John Harrison <john_androni...@hotmail.comwrote:
>Peter wrote:
>>I right now reading this book.
And he is iterating some points I'm following since 1996, e.g.
exception safety.
But e.g. he is missing one of the major exception safety guidelines,
which is
>>Allocate only a single resource inside a constructor body (deallocate
in the matching destructor body).
Chain such classes into base-class/member-class relationships.
This way you are able to exploit the code generation features of the
compiler,
since you wont have to deal with partially constructed objects and
cleanup after an exception has been thrown.
>>I was thinking that this rule is already in broad usage and should be
part of any modern book on C++.
>Effective C++ is not that modern a book is it, 10 years old according to
Amazon.
>Your criticism is valid I guess, but Effective C++ is a beginners book,
and exception safety is an advanced topic.
>It remains an exceptionally good book, taught me more about C++ than any
other single book I've read.
>john
can you suggest a good book for advanced topic in c++? e.g. the
exception safety that you mention?

There's a series of books that grew out of the guru of the week column
(http://www.gotw.ca/gotw/), the first is called Exceptional C++ by Herb
Sutter.

Personally I didn't like the style much, but the material covered is good.

john
these books are good, but their style is too tiresome. I never could
finish this books

Effective C++, More Effective C++, Effective STL and Modern C++ Design
serve well as reference guides because they are well organized

the organization of gotw books is too confusing. I think a clipping or
a reedition may be of great help in order to get the valuable material
of Herb Sutter (exception safety is his best approach, imho)

Diego

Feb 27 '07 #16

This discussion thread is closed

Replies have been disabled for this discussion.