May 22, 2018
On 5/22/18 1:01 AM, Manu wrote:
> On 21 May 2018 at 15:51, Steven Schveighoffer via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>> On 5/21/18 6:37 PM, Manu wrote:
>>>
>>> On 21 May 2018 at 15:29, Steven Schveighoffer via Digitalmars-d
>>> <digitalmars-d@puremagic.com> wrote:
>>>>
>>>> Uninitialized, but allocated and usable. The difference between this and
>>>> delete is that delete is going to unallocate that memory. The next time
>>>> it's
>>>> allocated, it will be overwritten with an init pattern for the new type.
>>>>
>>>> Basically, in D when you have access to memory, it should be in a valid
>>>> state.
>>>
>>>
>>> Why is it reasonable to expect that the buffer after `destroy()`
>>> should be 'valid'?
>>> Who's to say that the init state is 'valid'?
>>
>>
>> It's valid in that it's not garbage, and that it's not full of dangling
>> pointers.
> 
> Ah! Dangling pointers... that might conservatively retain garbage.
> That's a good reason.

Well, I was thinking more along the lines of accessing memory that is no longer valid :) A destructor can, for instance, free C malloced memory.

>>> And you've demonstrated exactly what I'm saying... there's no need for
>>> destroy() to return initialised memory here. It could return
>>> 0xfeeefeee memory or something (for debugging purposes).
>>
>>
>> No, the ctor assumes all values are in init state. If that's not the case,
>> then the code will crash or corrupt memory.
> 
> ....so, assign init immediately before construction? Rather than
> assigning init on destruction, which makes destroy more expensive, and
> it may or may not be re-used (most likely not).
> Why isn't assigning init built into the constructor?

It provides for slight efficiencies. For example, if you allocate an array of 100 structs, whose init value is all 0, you can do one memset on the entire array.

When you split the init blitting from the constructor, you have more options.

Note: you can "destroy" without blitting init, all the tools are there (the same ones destroy uses, it's not a magic function). Might be a good addition -- unsafeDestroy.

-Steve
May 22, 2018
On 22 May 2018 at 06:44, Steven Schveighoffer via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On 5/22/18 1:01 AM, Manu wrote:
>>
>> On 21 May 2018 at 15:51, Steven Schveighoffer via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>>
>>> On 5/21/18 6:37 PM, Manu wrote:
>>>>
>>>>
>>>> On 21 May 2018 at 15:29, Steven Schveighoffer via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>>>>
>>>>>
>>>>> Uninitialized, but allocated and usable. The difference between this
>>>>> and
>>>>> delete is that delete is going to unallocate that memory. The next time
>>>>> it's
>>>>> allocated, it will be overwritten with an init pattern for the new
>>>>> type.
>>>>>
>>>>> Basically, in D when you have access to memory, it should be in a valid state.
>>>>
>>>>
>>>>
>>>> Why is it reasonable to expect that the buffer after `destroy()`
>>>> should be 'valid'?
>>>> Who's to say that the init state is 'valid'?
>>>
>>>
>>>
>>> It's valid in that it's not garbage, and that it's not full of dangling pointers.
>>
>>
>> Ah! Dangling pointers... that might conservatively retain garbage. That's a good reason.
>
>
> Well, I was thinking more along the lines of accessing memory that is no longer valid :) A destructor can, for instance, free C malloced memory.

The memory post-destruction is invalid... nobody will access it. Accessing it should be undefined behaviour until such a time as the memory is re-constructed with a new instance...
May 23, 2018
On 5/22/18 9:48 PM, Manu wrote:
> On 22 May 2018 at 06:44, Steven Schveighoffer via Digitalmars-d
> <digitalmars-d@puremagic.com> wrote:
>> On 5/22/18 1:01 AM, Manu wrote:
>>> Ah! Dangling pointers... that might conservatively retain garbage.
>>> That's a good reason.
>>
>>
>> Well, I was thinking more along the lines of accessing memory that is no
>> longer valid :) A destructor can, for instance, free C malloced memory.
> 
> The memory post-destruction is invalid... nobody will access it.
> Accessing it should be undefined behaviour until such a time as the
> memory is re-constructed with a new instance...
> 

This particular sub-thread was about using destroy on something, not freeing the memory. The memory is not invalid.

To clarify, I'm talking about something like this:

struct S
{
  int *foo;
  this(int x) { foo = cast(int*)malloc(int.sizeof); }
  ~this() { free(foo); }
}

auto s = S(1);
destroy(s);
*s.foo = 5; // oops

If s.foo is reset to null, then you get a nice predictable segfault. If not, then you get memory corruption. Sure you can just say "undefined behavior", but I'd rather the defined behavior.

-Steve
May 23, 2018
On 20 May 2018 at 13:25, Walter Bright via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On 5/20/2018 12:28 PM, Manu wrote:
>>
>> I've started digging at some surfac-ey extern(C++) issues.
>
>
> I've improved the definition of how construction works, such as when the .init happens, in the spec.
>
> https://dlang.org/spec/class.html#constructors
>
>> Is __xdtor **always** present?
>
> No. If it's POD, it is not. When it is added, it is added as an AliasDeclaration, not a FuncDeclaration. See buildDtor() in clone.d, which is where it is created.
>
> You can also see in that function how _ArrayDtor and __fieldDtor are built on demand, and the order in which they are called.

Yup, I'm onto it. Check out my PR!
May 23, 2018
On 23 May 2018 at 06:36, Steven Schveighoffer via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> On 5/22/18 9:48 PM, Manu wrote:
>>
>> On 22 May 2018 at 06:44, Steven Schveighoffer via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>>>
>>> On 5/22/18 1:01 AM, Manu wrote:
>>>>
>>>> Ah! Dangling pointers... that might conservatively retain garbage. That's a good reason.
>>>
>>>
>>>
>>> Well, I was thinking more along the lines of accessing memory that is no longer valid :) A destructor can, for instance, free C malloced memory.
>>
>>
>> The memory post-destruction is invalid... nobody will access it. Accessing it should be undefined behaviour until such a time as the memory is re-constructed with a new instance...
>>
>
> This particular sub-thread was about using destroy on something, not freeing the memory. The memory is not invalid.
>
> To clarify, I'm talking about something like this:
>
> struct S
> {
>   int *foo;
>   this(int x) { foo = cast(int*)malloc(int.sizeof); }
>   ~this() { free(foo); }
> }
>
> auto s = S(1);
> destroy(s);
> *s.foo = 5; // oops
>
> If s.foo is reset to null, then you get a nice predictable segfault. If not, then you get memory corruption. Sure you can just say "undefined behavior", but I'd rather the defined behavior.

Yeah no... I'm happy with "accessing uninitialised memory is undefined
behaviour".
If you want defined behaviour; initialise the memory!
1 2
Next ›   Last »