避免创建临时对象造成的内存泄漏
Avoid memory leak from creating temporary objects
在 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();
}
}
}
我必须一次做一个加法,一次删除一个结果。
有没有更好的方法来处理这些临时变量的销毁?
我能想到的最佳解决方案是将其从 class
更改为 struct
。我不确定如何将 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();
}
}
}
我首先想到的是使用 mixin,这似乎是完美的解决方案,但它不支持运算符。
另一种替代方法是将结果包装在一个结构中,然后将该结构隐式转换回 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);
}
}
当然,我会避免运算符重载,除非它真的......真的很有意义,并且永远不会 return 来自没有关键字的函数的堆实例,例如 'create' 或 'new' 在函数名称中。
旁注,在这种特定情况下,您可以只使用 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);
}
同样,我不建议这样做。
在 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();
}
}
}
我必须一次做一个加法,一次删除一个结果。
有没有更好的方法来处理这些临时变量的销毁?
我能想到的最佳解决方案是将其从 class
更改为 struct
。我不确定如何将 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();
}
}
}
我首先想到的是使用 mixin,这似乎是完美的解决方案,但它不支持运算符。
另一种替代方法是将结果包装在一个结构中,然后将该结构隐式转换回 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);
}
}
当然,我会避免运算符重载,除非它真的......真的很有意义,并且永远不会 return 来自没有关键字的函数的堆实例,例如 'create' 或 'new' 在函数名称中。
旁注,在这种特定情况下,您可以只使用 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);
}
同样,我不建议这样做。