1

对不起,我知道在 C++ 中返回局部变量的引用或指针会导致 bad_reference 异常。我不确定它在 C# 中的情况如何?

例如

List<StringBuilder> logs = new List<StringBuilder>();
void function(string log)
{
   StringBuilder sb = new StringBuilder();
   logs.Add(sb);
}

在这个函数中,一个本地对象被创建并存储在一个列表中,这是坏的还是必须以另一种方式完成。我真的很抱歉问这个问题,但是在编写 C++ 2 个月后我很困惑。

谢谢。

4

4 回答 4

1

在 C# 中,垃圾收集器管理您创建的所有(托管)对象。除非不再有对它的任何引用,否则它不会删除它。

所以该代码是完全有效的。logs保留对StringBuilder. 垃圾收集器知道这一点,因此即使在最初创建它的上下文超出范围后,它也不会清理它。

于 2012-07-23T17:05:55.223 回答
1

在 C# 中,对象生命周期由 CLR 为您管理;与 C++ 相比,您必须将每个新的与删除相匹配。

但是在 C# 中你不能这样做

void fun()
{
    SomeObject sb(10);
    logs.Add(sb);
}

即在堆栈上分配你必须使用 new - 所以在这方面 C# 和 C++ 的工作方式相似 - 除了释放/释放对象引用时。

在 C# 中仍然有可能泄漏内存 - 但它比在 C++ 中更难。

于 2012-07-23T17:06:10.557 回答
1

您编写的代码没有任何问题。这主要是因为 C# 与任何 .NET 语言一样,是一种“托管”语言,可以为您进行大量内存管理。要在 C++ 中获得相同的效果,您需要显式使用一些第三方库。

为您清理一些基础知识:

在 C# 中,您很少直接处理“指针”或“引用”。如果需要,您可以处理指针,但这是“不安全”的代码,除非您知道自己在做什么,否则您真的会避免这种事情。在您处理引用(例如refout参数)的少数情况下,该语言会对您隐藏所有细节,并让您将它们视为普通变量。

相反,C# 中的对象被定义为引用类型的实例;每当您使用引用类型的实例时,它类似于使用指针,只是您不必担心细节。在 C# 中创建引用类型的新实例的方式与在 C++ 中创建对象的新实例相同,使用分配内存、运行构造函数等的运算符。在代码示例中,两者都是引用类型。newStringBuilderList<StringBuilder>

这里重要的托管语言的关键方面是自动垃圾收集。在运行时,.NET 框架“知道”您创建了哪些对象,因为您总是从它自己的内部管理的堆中创建它们(malloc在 C# 中没有直接或类似的东西)。它还“知道”一个对象何时完全超出范围——当您的程序中任何地方都没有对它的引用时。一旦发生这种情况,运行时就可以随时释放内存,通常是当它开始耗尽可用内存时,您永远不必这样做。事实上,在 C# 中没有办法显式销毁托管对象(尽管如果使用非托管资源,则必须清理它们)。

在您的示例中,运行时知道您已创建 aStringBuilder并将其放入 a List<>; 它会跟踪那个物体,只要它在里面,List<>它就会一直存在。一旦您将其从 中删除List<>,或者其List<>本身消失,运行时将自动StringBuilder为您清理 。

于 2012-07-23T17:14:05.847 回答
1

您的 C# 代码不返回对象引用,因此它不符合您的关注。然而,这是 C# 中不存在的问题。CLR 不允许您在堆栈上创建对象,只能在堆上创建对象。垃圾收集器确保对象引用保持有效。

于 2012-07-23T17:04:19.330 回答