Dlang — есть ли способ встраивать объекты в объекты?

В соответствии со спецификацией D все классы доступны по ссылке, что означает, что следующий класс будет расположен в памяти следующим образом.

Псевдокод:

class A
{
    public int c;
    public B b;
}

Схема памяти объекта типа A:

4 bytes | int c

(4/8) bytes | address of b

Есть ли способ создать класс, который бы встраивал b непосредственно в A вместо ссылки? Или я что-то упускаю?


person Community    schedule 10.03.2016    source источник


Ответы (3)


Scoped оказался лучше, чем я думал, вы также можете использовать emplace, который немного более громоздкий в этом простом случае, но может пригодиться:

class A {
    import std.conv;

    public  B b;

    // We can't just use sizeof here because we want the size of the
    // instance, not the reference.
    private void[__traits(classInstanceSize, B)] b_space;

    this() {
        b = emplace!B(b_space);
    }
}
person cym13    schedule 10.03.2016
comment
Однако вам все равно нужно учитывать выравнивание, и в этом случае в шаблоне scoped!B все это уже будет реализовано. - person ratchet freak; 10.03.2016
comment
Я хочу сказать, что, хотя этот ответ был принят, я тоже думаю, что в большинстве случаев решение на основе scoped!B было бы лучше. - person cym13; 17.03.2016

Есть несколько вариантов:

Сначала вы можете сделать B типом структуры, если вам не нужна семантика ref, то просто не делайте его классом в первую очередь.

В противном случае вы можете использовать scoped!B для размещения b на месте.

import std.typecons;
class A
{
    public int c;
    public scoped!B b;
}

В обоих случаях дескруктор B будет вызываться, когда A, содержащий его, будет уничтожен.

person ratchet freak    schedule 10.03.2016
comment
scoped не будет выделяться на месте, это всего лишь структура-оболочка вокруг класса для детерминированного уничтожения - person cym13; 10.03.2016
comment
Имеет ли использование struct или scoped!B какие-либо последствия? Гарантирует ли scoped!B, что сборщик мусора не будет вызван? Спасибо за ваше время! - person ; 10.03.2016
comment
@cym13 Прошу не согласиться это структура со статическим массивом размером с экземпляр + выравнивание. - person ratchet freak; 10.03.2016
comment
@ChristianVeenman scoped!B будет очищен, когда в то же время A, содержащий его, будет очищен. - person ratchet freak; 10.03.2016
comment
@ cym13 В документации даже прямо говорится, что это позволит избежать накладных расходов на new Это не то, что может сделать оболочка вокруг ссылки. - person ratchet freak; 10.03.2016

scoped!T в ответе выше это функция, а не тип; поэтому данный пример не будет работать. Причина в том, что классы должны быть инициализированы вызовом конструктора.

В качестве обходного пути используйте typeof() и инициализируйте член в конструкторе класса:

import std.typecons;
class B { }
class A {
    public int c;
    public typeof(scoped!B()) b;
    this() {
        this.b = scoped!B();
    }
}

Обратите внимание, что хотя строка в конструкторе выглядит как присваивание, она корректно интерпретируется как конструкция.

person Marc Schütz    schedule 11.03.2016