Topic: 3.8.7 Object lifetime example (N3000)


Author: "Leigh Johnston" <leigh@i42.co.uk>
Date: Tue, 16 Feb 2010 16:35:05 CST
Raw View
Hi,

I am slightly worried by the example in 3.8.7, specifically the following
line:

new (this) C(other); // new object of type C created

Although not the case in this example if C's copy constructor could throw an
exception a destructor could be erroneously called (destruction of c1 in the
example during stack unwinding).

I think the following change would "fix" this or make it less confusing at
least:

new (this) C(other); // new object of type C created

becomes

new (this) C(other); // new object of type C created (C's implicitly defined
copy constructor should never throw an exception)

/Leigh


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Pete Becker <pete@versatilecoding.com>
Date: Tue, 16 Feb 2010 18:04:39 CST
Raw View
Leigh Johnston wrote:

> Hi,
>
> I am slightly worried by the example in 3.8.7, specifically the following
> line:
>
> new (this) C(other); // new object of type C created
>
> Although not the case in this example if C's copy constructor could throw
> an
> exception a destructor could be erroneously called (destruction of c1 in
> the
> example during stack unwinding).
>
> I think the following change would "fix" this or make it less confusing at
> least:
>
> new (this) C(other); // new object of type C created
>
> becomes
>
> new (this) C(other); // new object of type C created (C's implicitly
> defined
> copy constructor should never throw an exception)
>
>
Unfortunately, people seem to read this example of how lifetimes work as
recommending this approach to coding. Anybody who writes code like this
deserves whatever happens to them.

--
 Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of
"The Standard C++ Library Extensions: a Tutorial and Reference"
(www.petebecker.com/tr1book)

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Goran <goran.pusic@gmail.com>
Date: Wed, 17 Feb 2010 11:17:07 CST
Raw View
On Feb 16, 11:35 pm, "Leigh Johnston" <le...@i42.co.uk> wrote:
> Hi,
>
> I am slightly worried by the example in 3.8.7, specifically the following
> line:
>
> new (this) C(other); // new object of type C created
>
> Although not the case in this example if C's copy constructor could throw an
> exception a destructor could be erroneously called (destruction of c1 in the
> example during stack unwinding).

What you say is correct. What's done there is __not__ what one should
do as a normal course of action. One __can__ do that when C(const C&)
does not throw. But even then, that line you've shown most often
likely should be preceded by this->~C(). That is, "this" should likely
be "destroyed" as a normal course of action (although one could
imagine a situation where even this is not needed).

Correct way is to have assignment operator and do simply

*this = other;

Wrong reasons why people do this sort of thing:
* they don't know any better
* laziness (prick couldn't be bothered to write assignment operator)
* premature optimization ("I know, I'll recreate object in-place,
that'll be faster!")

Goran.

P.S. What's 3.8.7. and N3000, BTW?


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Leigh Johnston" <leigh@i42.co.uk>
Date: Wed, 17 Feb 2010 16:24:35 CST
Raw View
> Correct way is to have assignment operator and do simply
>
> *this = other;
>
>
I disagree, this results in infinite recursion (or finite with stack fault
given a finite stack size)!  You probably meant something slightly
different. :)

/Leigh

--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Pete Becker <pete@versatilecoding.com>
Date: Wed, 17 Feb 2010 16:27:09 CST
Raw View
Goran wrote:

> On Feb 16, 11:35 pm, "Leigh Johnston" <le...@i42.co.uk> wrote:
>
>> Hi,
>>
>> I am slightly worried by the example in 3.8.7, specifically the following
>> line:
>>
>> new (this) C(other); // new object of type C created
>>
>> Although not the case in this example if C's copy constructor could throw
>> an
>> exception a destructor could be erroneously called (destruction of c1 in
>> the
>> example during stack unwinding).
>>
>
> What you say is correct. What's done there is __not__ what one should
> do as a normal course of action. One __can__ do that when C(const C&)
> does not throw. But even then, that line you've shown most often
> likely should be preceded by this->~C(). That is, "this" should likely
> be "destroyed" as a normal course of action (although one could
> imagine a situation where even this is not needed).
>
> Correct way is to have assignment operator and do simply
>
> *this = other;
>
> Wrong reasons why people do this sort of thing:
> * they don't know any better
> * laziness (prick couldn't be bothered to write assignment operator)
> * premature optimization ("I know, I'll recreate object in-place,
> that'll be faster!")
>
>
Or "wow, that's cool!"

Goran.
>
> P.S. What's 3.8.7. and N3000, BTW?
>
>
>
N3000 is the current working draft for C++0x (there's a newer one in the
pipeline, but it's a couple days away at the moment). 3.8.7 is the section
number of the text under discussion. Well, actually, it should be 3.8/7,
that is, paragraph 7 in section 3.8. If you have the current standard, it's
3.8/5.

--
 Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of
"The Standard C++ Library Extensions: a Tutorial and Reference"
(www.petebecker.com/tr1book)

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Leigh Johnston" <leigh@i42.co.uk>
Date: Wed, 17 Feb 2010 16:25:17 CST
Raw View

"Goran" <goran.pusic@gmail.com> wrote in message
news:9af8d152-6452-46f9-8f6c-488212df22df@b2g2000yqi.googlegroups.com...

> On Feb 16, 11:35 pm, "Leigh Johnston" <le...@i42.co.uk> wrote:
>
>> Hi,
>>
>> I am slightly worried by the example in 3.8.7, specifically the following
>> line:
>>
>> new (this) C(other); // new object of type C created
>>
>> Although not the case in this example if C's copy constructor could throw
>> an
>> exception a destructor could be erroneously called (destruction of c1 in
>> the
>> example during stack unwinding).
>>
>
> What you say is correct. What's done there is __not__ what one should
> do as a normal course of action. One __can__ do that when C(const C&)
> does not throw. But even then, that line you've shown most often
> likely should be preceded by this->~C(). That is, "this" should likely
> be "destroyed" as a normal course of action (although one could
> imagine a situation where even this is not needed).
>

The example I am referring to does have "this->~C()" before the placement
new yes, which is part of the problem: object is now destroyed and can be
erroneously destroyed a second time if the copy constructor throws as the
object is (was) on the stack.


> Correct way is to have assignment operator and do simply
>
> *this = other;
>
> Wrong reasons why people do this sort of thing:
> * they don't know any better
> * laziness (prick couldn't be bothered to write assignment operator)
> * premature optimization ("I know, I'll recreate object in-place,
> that'll be faster!")
>
> Goran.
>

Yes I know this which is the reason why I posted with my worries about this
example as it is not exception safe when considered as a general "pattern" -
not good quality for something in a standard document I reckon.


> P.S. What's 3.8.7. and N3000, BTW?
>
>
Section 3.8.7 of the draft C++0x standard (v N3000).

/Leigh



--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: =3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D <daniel.kruegler@googlemail.c=.om>
Date: Wed, 17 Feb 2010 16:24:54 CST
Raw View
On 17 Feb., 18:17, Goran <goran.pu...@gmail.com> wrote:
> P.S. What's 3.8.7. and N3000, BTW?

N3000 is a public accessible document of the current working
/draft/ of the upcoming C++0x standard. Just visit

http://www.open-std.org/jtc1/sc22/wg21/

search for the "papers" link at the top, then select the most
recent 2009 block, unit "2009-11 post-Santa Cruz mailing".
In the list of papers you'll find

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n3000.pdf

3.8.7 is a wrong quote. It is supposed to mean 3.8/7 or
[basic.life]/p. 7

HTH & Greetings from Bremen,

Daniel Kr=FCgler


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Goran <goran.pusic@gmail.com>
Date: Thu, 18 Feb 2010 11:19:34 CST
Raw View
On Feb 17, 11:24 pm, "Leigh Johnston" <le...@i42.co.uk> wrote:
> > Correct way is to have assignment operator and do simply
>
> > *this = other;
>
> I disagree, this results in infinite recursion (or finite with stack fault
> given a finite stack size)!

Eh? No, it doesn't. Why would it? What exactly did you do to get
recursion (code snippet)?

Goran.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: "Leigh Johnston" <leigh@i42.co.uk>
Date: Fri, 19 Feb 2010 14:47:27 CST
Raw View

"Goran" <goran.pusic@gmail.com> wrote in message
news:4b9a51fe-4334-45e1-86d5-c0da965dc668@q29g2000yqn.googlegroups.com...
> On Feb 17, 11:24 pm, "Leigh Johnston" <le...@i42.co.uk> wrote:
>> > Correct way is to have assignment operator and do simply
>>
>> > *this = other;
>>
>> I disagree, this results in infinite recursion (or finite with stack
>> fault
>> given a finite stack size)!
>
> Eh? No, it doesn't. Why would it? What exactly did you do to get
> recursion (code snippet)?
>
> Goran.
>

foo& foo::operator=(const foo& other)
{
   *this = other;  // this is recursive, i.e. it calls itself again.
   return *this;
}

/Leigh


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Goran <goran.pusic@gmail.com>
Date: Mon, 22 Feb 2010 13:04:10 CST
Raw View
On Feb 19, 9:47 pm, "Leigh Johnston" <le...@i42.co.uk> wrote:
> > Eh? No, it doesn't. Why would it? What exactly did you do to get
> > recursion (code snippet)?
>
> > Goran.
>
> foo& foo::operator=(const foo& other)
> {
>    *this = other;  // this is recursive, i.e. it calls itself again.
>    return *this;
>
> }

Ah... OK, here's where misunderstanding arose: when I wrote that one
should have operator= and simply do *this = other, I did not mean (nor
say) that one should do *this = other inside operator=. I merely
wanted to say that one should not use... ahem... "fake copy
construction with placement new", but simply operator=. But it seems
that in your example they did it __inside__ operator= (did they? I
didn't look). If so, whoops, yes, you're right, it is indeed an
infinite recursion.

BTW, requiring that copy constructor must not throw is not good
enough. For example, it is sufficient to have member of C that has a
non-trivial destructor (e.g. frees a resource). That easily leaks
memory (said member is constructed two times, but destructed once, so
a resource is leaked once).

Goran.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]