Date: Thu, 16 Jan 2014 12:01:26 -0800
On Thu, Jan 16, 2014 at 11:44 AM, Herb Sutter <hsutter_at_[hidden]> wrote:
>> | struct B { int x; }; // 1
>> | void* p = malloc(sizeof(B)); // 2
>> | B* pb = static_cast<B*>(p); //3
>> | pb->x = 17; // 4
>> |
>> | I take it as obvious that the lifetime of an object of type B has
>> | begun somewhere in this code snippet. Now the question is: which
>> | specific line begins that lifetime? As you say, casting a pointer
>> | doesn't begin or end a lifetime; I think we can rule out line 3 as the
>> | one that begins the lifetime of that B object. Line 1 doesn't look too
>> promising either.
>>
>> Well, in fact I don't take it obvious that the lifetime of an object has even
>> begun!
>> I don't even see that or object has been constructed or initialized.
>
> Agreed. I would expect line 4 to be at least unspecified behavior and probably undefined behavior.
I feel like I must have missed part of the conversation.
We want to utterly break compatibility with C (and C-like C++ code) here?
struct B { int x };
struct B* p = (B*) malloc(sizeof(B));
p->x = 17;
This (modulo the cast) has been how C has handled dynamic allocation
of structs approximately forever. There are no constructors in C,
structs don't get initialized, their fields just get assigned to.
When compiled as C++, no constructor is called here either. And we've
allowed that.
The issue we're dealing with here is that C allowed writing to a
suitably-aligned chunk of memory (from malloc(), at least) as if it
were an object. There is no process whereby the storage _becomes_ an
object. You just use it.
We can't adopt a stricter model without breaking existing code. I'm
fine with breaking existing code, except that I suspect we'd break so
much that it would never all get fixed, and it's a silent breaking
change in many cases.
-- James
>> | struct B { int x; }; // 1
>> | void* p = malloc(sizeof(B)); // 2
>> | B* pb = static_cast<B*>(p); //3
>> | pb->x = 17; // 4
>> |
>> | I take it as obvious that the lifetime of an object of type B has
>> | begun somewhere in this code snippet. Now the question is: which
>> | specific line begins that lifetime? As you say, casting a pointer
>> | doesn't begin or end a lifetime; I think we can rule out line 3 as the
>> | one that begins the lifetime of that B object. Line 1 doesn't look too
>> promising either.
>>
>> Well, in fact I don't take it obvious that the lifetime of an object has even
>> begun!
>> I don't even see that or object has been constructed or initialized.
>
> Agreed. I would expect line 4 to be at least unspecified behavior and probably undefined behavior.
I feel like I must have missed part of the conversation.
We want to utterly break compatibility with C (and C-like C++ code) here?
struct B { int x };
struct B* p = (B*) malloc(sizeof(B));
p->x = 17;
This (modulo the cast) has been how C has handled dynamic allocation
of structs approximately forever. There are no constructors in C,
structs don't get initialized, their fields just get assigned to.
When compiled as C++, no constructor is called here either. And we've
allowed that.
The issue we're dealing with here is that C allowed writing to a
suitably-aligned chunk of memory (from malloc(), at least) as if it
were an object. There is no process whereby the storage _becomes_ an
object. You just use it.
We can't adopt a stricter model without breaking existing code. I'm
fine with breaking existing code, except that I suspect we'd break so
much that it would never all get fixed, and it's a silent breaking
change in many cases.
-- James
Received on 2014-01-16 21:01:27