对于你认为的这个问题,面试的最佳答案是什么?
我想我在这里没有找到这个的副本,如果有,请链接它。
- 我不会在面试中问这个问题,因为我喜欢问与实际工作经验有关的问题,无论是过去还是将来。如果你想通过一些模糊的角落案例了解某人的原因,或者想了解他们对在面试中被提出这样一个问题的反应,那么它可能适合于一组更大的问题。否则,这基本上就是琐事。我会给他们一些建议,让他们好好考虑一下,并指出这可能是你在野外不会遇到的事情。提到这是一个毫无意义的问题,可能会赢得分数,这取决于他们是如何做到的。
- 我知道一个他们在面试时问这个问题的地方。我以为有各种各样的路可以走。我喜欢目前被否决的答案。另外,据我所知,这位面试官并没有问关于lambdas/linq的问题,但他确实问了一个非常没用的问题(imho)。尤其是因为我知道域离结构级别非常远,而且我相信该项目中的结构不到0.5%,实际数量可能更小。这么奇怪的问题,确实,也真的不确定他们想在那里测试什么。
- 附言:鉴于以上描述,我怀疑提到这是一个无稽之谈,会在这样的面试中为我们赢得分数:)下一个问题当然是——我们真的想在那里工作吗?
- 是的,对于那个面试官来说,指出他在问一些琐碎的事情可能不太好。作为一个面试官,我会的。这就是我要说的:)至于lambda和linq问题,我不会回避它们,但除非候选人表现出兴趣,否则我不会询问它们。语言特征是伟大的,衡量他们对语言特征的兴趣是重要的。但是我会等到他们表明他们知道并且对这些语言特性感兴趣,直到我直接询问他们。与设计模式、依赖注入、各种.NET库和许多其他功能相同。
- 嗯,这越来越有趣了。你能详细描述一下"候选人表现出兴趣"吗?假设候选人坐在你对面,和往常一样压力不大。他是如何开始对诸如di、linq、patterns等各种各样的主题表现出兴趣的,除非你自己问他关于这些主题的问题?
- @瓦伦廷库布:你让他/她谈论他们最近参与的项目。虽然他们最近的项目只可能涉及到那些具体的事情(LINQ、模式等),但他们不可避免地会涉及一些值得进一步询问的问题,比如候选人是否对该项目有真正的兴趣。
- 我不会一直这样。有些职位需要温暖的身体,有些需要优秀的团队成员,有些需要能在你的团队中开拓进取的人。所以这取决于候选人和职位。如果有人不成比例地被压制到他们的水平,你可能会认为他们的职位不太重要,或者完全基于软技能而取消他们的资格。不过,放松他们在一定程度上是你的工作——这条街道有两条路):除此之外,就像乔尔所说的,另外,询问关于课外节目的兴趣是可以的,尤其是在他们的简历上。
另一种看待这一点的方法——而不仅仅是引用说明结构不能/不具有析构函数的规范——考虑如果规范被更改,那么会发生什么——或者更确切地说,让我们问一个问题:我们能猜出为什么语言设计者决定不允许结构首先具有"析构函数"?
(这里不要挂断"析构函数"这个词;我们主要讨论的是一个神奇的结构方法,当变量超出范围时,它会自动被调用。换句话说,类似C++的析构函数的语言特征。
首先要意识到的是,我们不在乎释放记忆。无论对象是在堆栈上还是在堆上(例如,类中的结构),内存迟早都会以某种方式处理;要么从堆栈中弹出,要么收集。最初拥有类似于析构函数的东西的真正原因是为了管理外部资源——比如文件句柄、窗口句柄,或者其他需要特殊处理才能清除它们的东西,而clr本身并不知道。
现在假设您允许一个结构有一个析构函数来完成这个清理。好的。直到您认识到当结构作为参数传递时,它们都是通过值传递的:它们是被复制的。现在有两个具有相同内部字段的结构,它们都将尝试清理同一对象。一个会先发生,所以使用另一个的代码随后会开始神秘地失败…然后它自己的清理就会失败(希望!-最糟糕的情况是,它可能会成功地清除其他一些随机资源——例如,在重用句柄值的情况下,这种情况可能会发生。)
可以想象,对于作为参数的结构,您可以做一个特殊的例子,这样它们的"析构函数"就不会运行(但要小心-现在需要记住,当调用函数时,它始终是外部的"拥有"实际资源-因此,现在一些结构与其他结构有细微的不同…)-但是您仍然对regul有这个问题。结构变量,其中一个可以分配给另一个,生成一个副本。
你也许可以通过添加一个特殊的机制来完成分配操作,这使得新的结构可以用新的副本来协商底层资源的所有权——也许他们共享它,或者将所有权从旧的转移到新的-但是现在你已经基本上进入了C++的土地,在那里你需要拷贝CO。nstructor、赋值操作符和添加了一系列微妙的内容,等待捕获不知情的新手程序员。并且记住C语言的整个点是尽可能避免这种类型的C++复杂度。
而且,正如另一个答案所指出的那样,为了让事情变得更加混乱,结构不仅仅作为局部对象存在。对于局部变量,范围是好的并且定义得很好;但是结构也可以是类对象的成员。在这种情况下,何时应该调用"析构函数"?当然,您可以在容器类完成时执行此操作;但是现在您有了一种机制,根据结构所在的位置,它的行为会非常不同:如果结构是本地的,则在作用域结束时立即触发;如果结构在类中,则会延迟触发…因此,如果您真的关心确保某个结构中的某个资源在某个特定的时间被清理掉,并且如果您的结构最终可能成为类的成员,那么您可能需要像IDisposable/Using()这样的明确的东西来确保您的基础被覆盖。
因此,虽然我不能声称我是语言设计师,但我可以很好地猜测,他们决定不包括这样一个功能的原因之一是,这将是一个蠕虫罐头,他们希望保持C相当简单。
- 一个伟大的答案!实际上,我总是为这种类型的问题寻求这样的答案,"设计决策"而不是"最终决策"。+ 1。
- 只有当结构具有重写默认复制构造函数的方法时,析构函数才对结构有意义。
- +1个很好的答案。
- @超级跑车我完全同意。现在,问题是为什么不允许这样做?在我的例子中,我希望实现一个无障碍的引用计数系统,用于对象池。(为什么?因为在实时应用程序(如游戏)中,不确定的垃圾收集可能会导致死亡。对象池可以确保,除非存在严重的内存压力或某些显式的"加载"阶段,否则将重新使用内存,而不会取消分配。)
- @domi:如果结构不能有构造函数,那么数组只能通过用零填充新的分配来构造。支持结构构造器会使数组构造非常复杂,特别是考虑到(1)结构可能被嵌套,(2)构造器可能在初始化数组的过程中失败。
- "现在有两个具有相同内部字段的结构,它们都将尝试清理同一对象。其中一个将首先发生,因此随后使用另一个的代码将开始神秘地失败"—如果析构函数只调用Dispose(false),则允许多次调用Dispose(),而不会导致问题。这不意味着终结器可以多次调用而不会引起问题吗?
来自乔恩·贾格尔:
"结构不能有析构函数。析构函数只是伪装为object.Finalize的重写,而作为值类型的结构不受垃圾收集的影响。"
- 简明扼要。你的答案也是唯一一个没有错误地提到堆栈的答案。
- 如果结构超出范围(如果它是局部变量),为什么不运行终结器,或者当它是对象的一部分并且对象被垃圾收集时,为什么不运行终结器?如果一个结构可以实现IDisposable,为什么它不能有一个终结器?
- 如果结构包含在将在堆中的对象中,那么它是否被垃圾收集?
除数组和字符串之外的每个对象都以相同的方式存储在堆中:一个头,它提供有关"与对象相关"属性(其类型、是否由任何活动的监视器锁使用、是否具有非抑制的Finalize方法等)及其数据(即所有类型的实例字段(public、public、public)的信息。private和protected混合使用,基类字段出现在派生类型字段之前)。因为每个堆对象都有一个头,所以系统可以引用任何对象,并知道它是什么,以及垃圾收集器应该如何处理它。如果系统有一个已经创建的所有对象的列表,并且有一个Finalize方法,那么它可以检查列表中的每个对象,看看它的Finalize方法是否未被批准,并对其进行适当的操作。
结构存储时不带任何头;像Point这样有两个整型字段的结构只存储为两个整型。虽然可以将ref传递给结构(当结构作为ref参数传递时,就会创建这样的东西),但是使用ref的代码必须知道ref指向的是哪种类型的结构,因为ref和结构本身都不包含该信息。此外,堆对象只能由垃圾收集器创建,这将确保创建的任何对象在下一个GC周期之前始终存在。相比之下,用户代码可以自己创建和销毁结构(通常在堆栈上);如果代码创建了一个结构和一个ref,并将该结构传递给一个被调用的例程,那么在被调用的例程返回之前,代码无法销毁该结构(或做任何事情),因此该结构是有保证的至少在被调用的例程退出之前存在。另一方面,一旦被调用的例程退出,那么给定的ref应该被假定为无效,因为调用方可以在此后的任何时间任意销毁该结构。
因为根据定义,析构函数用于析构函数类的实例,而结构是值类型。
参考:http://msdn.microsoft.com/en-us/library/66x5fx1b.aspx
用微软自己的话来说:"Destructors are used to destruct instances of classes.",所以问"为什么你不能在(不是类的东西)上使用析构函数?"有点傻。^ ^
- 好吧,这种"定义之路"很迂腐,但我不确定接受采访的最佳路线。然而,在某些情况下,我可以看到这种方法的优点。当我们被问到"为什么平行线不相交?"答案"按定义"似乎比我认为的更合适。
- 我同意"按定义"的措辞是好的,所以我做了花呢:)
- 这里的问题是:许多问题都可以这样回答,但是更好的答案也经常存在。虽然这将是一个完全正确的答案,但在大多数情况下,它不会得到我们的分数。
- 啊,我终于明白你的意思了。是的,说得对。
- 析构函数不会析构函数类的实例。他们的角色,尽管他们的名字很不幸,但是允许班级执行需要执行的、他们自己能够执行的操作。例如,如果"某人"要求系统打开一个文件,系统将创建一个文件句柄,并向请求者提供该句柄,并承诺具有该句柄的人可以独占访问该文件,直到具有该句柄的人表示不再需要这样的访问。持有这样一个句柄的"文件"类有责任确保系统在不再需要时被告知。
- 否则,系统将无法知道没有人仍然拥有文件句柄的副本,因此将无限期地保持文件打开,以独占不再存在的实体。具有讽刺意味的是,破坏者不会破坏阶级,而是推迟他们的破坏,直到他们所有的事情都被整理好。
- Supercat,感谢您提供更多信息。所以你是说微软自己的定义是错误的?(老实说,这不会让我震惊)。
- 在微软的网站上有很多建议,这些建议可能曾经很有价值,但现在还远远不是最好的做事方式。Finalize比Cleanup更具描述性,不过NotifyOfBandonment会更好。