Избегайте утечки памяти при создании временных объектов - PullRequest
0 голосов
/ 30 января 2020

В Beef у меня может быть такой код:

using System;

namespace Program
{
    class Foobar 
    {
        public int value;

        public this(int val)
        {
            value = val;
        }

        public static Foobar operator+(Foobar lhs, Foobar rhs)
        {
            let result = new Foobar();
            result.value = lhs.value + rhs.value;
            return result;
        }
    }

    class Program
    {
        public static void Main()
        {
            Foobar a = scope:: Foobar(5);
            Foobar b = scope:: Foobar(5);

            Foobar c = a + b;
            defer delete c;

            Console.Write("{}", c.value);

            Console.In.Read();

        }
    }
}

, и это прекрасно работает, потому что я могу легко удалить выделение кучи, выполненное операцией a+b. Однако, если у меня есть:

using System;

namespace Program
{
    class Foobar 
    {
        public int value;

        public this(int val)
        {
            value = val;
        }

        public static Foobar operator+(Foobar lhs, Foobar rhs)
        {
            let result = new Foobar();
            result.value = lhs.value + rhs.value;
            return result;
        }
    }

    class Program
    {
        public static void Main()
        {
            Foobar a = scope:: Foobar(5);
            Foobar b = scope:: Foobar(5);
            Foobar x = scope:: Foobar(20);

            // Foobar c = (a + b) + x; // would leak

            Foobar temp = a + b;
            defer delete temp;

            Foobar c = temp + x;
            defer delete c;

            Console.Write("{}", c.value);
            Console.In.Read();

        }
    }
}

Я должен сделать одно добавление за раз и удалить каждый результат по одному.

Есть ли лучший способ справиться с уничтожением этих временных переменных?

Ответы [ 2 ]

1 голос
/ 21 апреля 2020

Первое, о чем я подумал, - это использование миксина, который кажется идеальным решением, однако он не поддерживает операторы.

Еще одна альтернатива - обернуть результат в структуру, а затем неявно вернуть обратно структуру. в FooBar. Идея состоит в том, что нам нужна промежуточная структура для обработки всего в стеке.

class Foobar {
    public int value;

    public this(int val) {
        value = val;
    }

    public static TempFoobar operator+(Foobar lhs, Foobar rhs) {
        let result = new Foobar(lhs.value + rhs.value);
        return TempFoobar(result);
    }
}

struct TempFoobar {
    Foobar result;
    public this(Foobar val) {
        result = val;
    }

    public void Replace(Foobar val) mut {
        delete result;
        result = val;
    }

    public static TempFoobar operator+(TempFoobar lhs, Foobar rhs) {
        var copy = lhs;
        let result = new Foobar(lhs.result.value + rhs.value);
        copy.Replace(result);
        return copy;
    }

    public static implicit operator Foobar(TempFoobar temp) {
         return temp.result;
    }
}


class Program {
    static mixin Add(Foobar lhs, Foobar rhs) {
        let result = scope:mixin Foobar(lhs.value + rhs.value);
        result
    }

    public static void Main() {
        Test();
        Console.In.Read();
    }

    public static void Test() {
        Foobar a = scope Foobar(5);
        Foobar b = scope Foobar(5);
        Foobar x = scope Foobar(20);
        //let c = Add!(Add!(a, b), x); //Mixin version
        Foobar c = (a + b) + x;
        defer delete c;
        Console.Write("{}", c.value);
    }
}

Конечно, я бы избежал перегрузки операторов, если это действительно ... действительно имеет смысл, и никогда не возвращал бы экземпляр кучи из функция без ключевого слова, такого как 'create' или 'new' в имени функции.

Примечание, в данном конкретном случае c вы можете просто использовать int в качестве промежуточного объекта

    public static int operator+(Foobar lhs, Foobar rhs)
    {
        return lhs.value + rhs.value;
    }

    public static int operator+(int lhs, Foobar rhs)
    {
        return lhs + rhs.value;
    }

    public static implicit operator Foobar(int temp) {
         return new Foobar(temp);
    }

Опять же, я не рекомендую делать это.

0 голосов
/ 31 января 2020

Лучшее решение, которое я могу придумать, это изменить его с class на struct. Я не уверен, как go сохранить Foobar как class и все же заставить это произойти:

using System;

namespace Program
{
    struct Foobar 
    {
        public int value;

        public this(int val)
        {
            value = val;
        }

        public static Foobar operator+(Foobar lhs, Foobar rhs)
        {
            return Foobar(lhs.value + rhs.value);
        }
    }

    class Program
    {
        public static void Main()
        {
            Foobar a = Foobar(5);
            Foobar b = Foobar(5);
            Foobar x = Foobar(20);

            Foobar c = (a + b) + x; 

            Console.Write("{}", c.value);
            Console.In.Read();

        }
    }
}
...