473,671 Members | 2,285 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Effective C++ by Scott Meyers

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
15 5918
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

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::constructo r()
bm2::constructo r()
Base::Base()
dm1::constructo r()
dm2::constructo r()
dm3::constructo r()
Derived::Derive d()

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
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
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::constructo r()
bm2::constructo r()
Base::Base()
dm1::constructo r()
dm2::constructo r()
dm3::constructo r()
Derived::Derive d()

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::Derive d() 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

"Salt_Peter " <pj*****@yahoo. comwrote in message
news:11******** *************@z 35g2000cwz.goog legroups.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::construct or()
bm2::construct or()
Base::Base()
dm1::construct or()
dm2::construct or()
dm3::construct or()
Derived::Deriv ed()

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::Derive d() 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
sks
"Peter" <pe****@xpedion .comwrote in message
news:11******** *************@h 3g2000cwc.googl egroups.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
* Peter:
>
"Salt_Peter " <pj*****@yahoo. comwrote in message
news:11******** *************@z 35g2000cwz.goog legroups.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::construc tor()
bm2::construc tor()
Base::Base( )
dm1::construc tor()
dm2::construc tor()
dm3::construc tor()
Derived::Deri ved()

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

"sks" <sk*@yahoo.comw rote in message
news:LN******** ***********@new sfe14.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 initSomeStructu re(someStructur e *_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 destroySomeStru cture(someStruc ture *_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("allocat ion of somestructure failed\n");
}
else
if (initSomeStruct ure(p))
{ free(p);
printf("Initial ization 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(v oid)
{
}
};
Usage of this code would look like this:

SomeStructure *p;
try
{ p = new SomeStructure;
} catch (const std::exception &_r)
{ cout << "Initializa tion 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<B m_sB;
std::auto_ptr<C m_sC;
std::auto_ptr<D m_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
On Feb 23, 4:47 pm, John Harrison <john_androni.. .@hotmail.comwr ote:
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

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

5
5772
by: Matt Priest | last post by:
I am trying to learn more about how to effectively mix low-level C code with C++. I am having trouble finding resources/papers/books that aren't in one or the other camp exclusively. Can anyone point me toward a good place to start? I want to understand how to make decisions about the development environment, code structure and planning, and any other issues that I'm not aware of that may be important to know. Thanks in advance!
25
7567
by: Matthias | last post by:
Hi, I am just reading that book by Scott Meyers. In Item 4 Meyers suggests to always use empty() instead of size() when probing for emptyness of STL containers. His reasoning is that size() might take linear time on some list implementations. That makes sense at first. However, he also says this at the very beginning: "That being the case , you might wonder why one construct should be preferred to the other, especially in view of the...
4
1974
by: John | last post by:
I am looking for a good Lock class implementation that has barely been implemented in Effective STL of Myers (Item 12). Any pointers? Is there an implementation that is good for both OpenMP and pthreads? Thanks, --j
4
2421
by: cfchou | last post by:
hi, i have one question about the item 31 of Meyers' More Effective c++. in page 234, section "Using Virtual Functions Only", it says that "for example, you decide to add a new class Satellite (inheriting from GameObject) to your game, you'd have to add a new collide function to each of the existing classes in the program". how come? i assume:
44
3864
by: Josh Mcfarlane | last post by:
Just out of curiosity: When would using std::list be more efficient / effective than using other containers such as vector, deque, etc? As far as I'm aware, list doesn't appear to be specialized for anything. Thanks, Josh McFarlane
15
1991
by: vikram_p_nayak | last post by:
I was just going through this book by Scott Meyers and did not fully follow item 10. Basically he says the constructor should catch all exceptions, do any cleanups necessary and then throw. This is because otherwise the member objects already created can not be destroyed from outside since the container object itself is not fully created. Look at this - (myclass contains objects of class1 and class2) Class myclass { class1 m_class1;
3
1561
by: Zongjun Qi | last post by:
Hey, In the book <Effective C++>, the author provides an example to prove why we need "pass by reference". I redoed the example, and found something interesting. The codes are: ############################## #include <iostream> class Student{ public:
7
3083
by: eric | last post by:
hello i'm confused by an example in the book "Effective C++ Third Edition" and would be grateful for some help. here's the code: class Person { public: Person(); virtual ~Person(); // see item 7 for why this is virtual ...
4
1894
by: jfwfmt | last post by:
Please pardon my ignorance. I'm writing a C++ STL program after not writing code for 7 years, I'm trying to invoke key_word.inc() using an iterator for a set containing key_word_T. The following is a pared down version. #include <cstdlib> #include <set> #include <string> using namespace std; class key_word { public:
0
8474
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8392
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
8912
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
8819
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
0
7428
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6222
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
4222
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
4403
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
2
2049
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.