代码之家  ›  专栏  ›  技术社区  ›  Michel

结构与类

  •  86
  • Michel  · 技术社区  · 14 年前

    我将在代码中创建100000个对象。它们很小,只有2到3个属性。我会把它们放在一个通用列表中,当它们出现时,我会循环它们并检查值 a b .

    将这些对象创建为类还是结构更快/更好?

    编辑

    a、 属性是值类型(除了我认为的字符串?)

    编辑2

    10 回复  |  直到 11 年前
        1
  •  134
  •   Robert Siemer    10 年前

    它是 更快

    你是唯一能决定那个问题答案的人。两种方法都试试, 一个有意义的、以用户为中心的、相关的性能度量,然后您将知道在相关场景中,更改是否对实际用户有意义。

    结构消耗更少的堆内存(因为它们是 较小的

    它是 更好的 要将这些对象创建为类还是结构?

    也许是类,也许是结构。根据经验:
    一。小的
    2。逻辑上不可变的值
    三。他们很多
    然后我会考虑把它变成一个结构。否则我会坚持使用引用类型。

    如果需要对结构的某个字段进行变异,通常最好构建一个构造函数,该构造函数返回一个完整的新结构,并且字段设置正确。可能稍微慢一点(测量一下!)但逻辑上更容易推理。

    垃圾收集器对堆和堆栈上的对象的处理是否相同?

    ,它们不一样,因为 堆栈上的对象是集合的根 . 垃圾收集器不需要问“堆栈上的这个东西还活着吗?”因为这个问题的答案总是“是的,在堆栈上”。(现在,你不能指望 保持

    但是垃圾收集员 必须将堆栈上的对象视为活动对象,就像它将已知的任何活动对象视为活动对象一样。堆栈上的对象可以引用需要保持活动状态的堆分配对象,因此为了确定活动集,GC必须将堆栈对象视为活动的堆分配对象。但很明显 为了压缩堆而被视为“活动对象”,因为它们本来就不在堆上。

        2
  •  23
  •   John Alexiou    5 年前

    有时 struct

    例子:

    Value[] list = new Value[N];
    for (int i = 0; i < N; i++)
    {
        list[i].id = i;
        list[i].isValid = true;
    }
    

    大约比

    Value[] list = new Value[N];
    for (int i = 0; i < N; i++)
    {
        list[i] = new Value(i, true);
    }
    

    Value 是一个 结构 id isValid ).

    struct Value
    {
        int id;
        bool isValid;
    
        public Value(int i, bool isValid)
        {
            this.i = i;
            this.isValid = isValid;
        }
    }
    

    另一方面是项目需要移动或选择值类型所有的复制将减慢你的速度。为了得到准确的答案,我怀疑你必须分析你的代码并测试它。

        3
  •  7
  •   kyndigs    14 年前

    结构可能看起来类似于类,但有一些重要的区别需要注意。首先,类是引用类型,结构是值类型。通过使用结构,您可以创建行为类似于内置类型的对象,并享受它们的好处。

    当调用类的新运算符时,它将被分配到堆中。但是,当您实例化一个结构时,它会在堆栈上创建。这将带来业绩增长。此外,您不会像处理类那样处理对结构实例的引用。您将直接使用struct实例。因此,在将结构传递给方法时,它是按值传递的,而不是作为引用传递的。

    更多信息:

    http://msdn.microsoft.com/en-us/library/aa288471(VS.71).aspx

        4
  •  6
  •   Paul Ruane    14 年前

    在这种情况下,当你把它们放在 List<> 列表<> (返回到一个数组中)使用结构会更高效、更节省内存。

    (不过,请注意,大型数组将在大型对象堆上找到它们的路径,如果它们的生存期很长,可能会对进程的内存管理产生不利影响。记住,记忆并不是唯一的考虑。)

        5
  •  4
  •   Jon Hanna    14 年前

    如果它们有值语义,那么您可能应该使用结构。如果它们有引用语义,那么您可能应该使用一个类。有一些例外,它们大多倾向于创建一个类,即使存在值语义,但从那里开始。

    至于第二次编辑,GC只处理堆,但是堆空间比堆栈空间大得多,所以把东西放在堆栈上并不总是成功的。除此之外,结构类型列表和类类型列表都将位于堆中,因此在本例中这与此无关。

    编辑:

    我开始考虑这个学期 邪恶的 有害的。毕竟,如果类不是主动需要的,那么使其可变是一个坏主意,而且我不排除使用可变结构的可能性。这是一个很糟糕的想法,以至于几乎总是一个坏主意,但大多数情况下,它只是不符合值语义,所以在给定的情况下使用结构是没有意义的。

    私有嵌套结构可能有合理的例外,在这种情况下,该结构的所有使用都被限制在非常有限的范围内。但这不适用于这里。

    实际上,我认为“它会变异,所以它是一个糟糕的缺陷”并不比继续讨论堆和堆栈要好多少(这至少对性能有一些影响,即使经常被误传)。”它变异了,所以 很可能 认为它具有值语义是没有意义的,所以它是一个糟糕的结构“只是略有不同,但重要的是,我认为。

        6
  •  3
  •   FMM    14 年前

    最好的解决办法是测量,再测量,然后再测量一些。可能有一些你正在做的事情的细节可能会使一个简单、容易的答案变得困难,比如“使用结构”或“使用类”。

        7
  •  3
  •   supercat    11 年前

    一个结构,在其核心,只不过是一个字段的集合。在.NET中,结构可以“假装”为对象,并且对于每种结构类型,.NET都隐式定义一个具有相同字段和方法的堆对象类型,这些字段和方法作为堆对象的行为将类似于对象。持有对此类堆对象的引用的变量(“装箱”结构)将显示引用语义,但直接持有结构的变量只是变量的聚合。

    我认为结构和类之间的混淆很大程度上源于结构有两个非常不同的用例,这两个用例应该有非常不同的设计准则,但是MS准则没有区分它们。有时需要一些行为类似对象的东西;在这种情况下,MS准则是相当合理的,尽管“16字节限制”可能更像24-32。然而,有时需要的是变量的聚合。用于此目的的结构应该只包含一堆公共字段,并且可能包含 Equals 超驰, ToString 覆盖,和 IEquatable(itsType).Equals 实施。用作字段聚合的结构不是对象,不应假装是。从结构上看,场的意义应该是“写在这个场上的最后一件事”。任何附加含义应由客户代码确定。

    例如,如果变量聚合结构具有成员 Minimum Maximum ,结构本身不应该保证 Minimum <= Maximum . 接收参数这样的结构的代码应该表现得好像它是单独传递的 价值观。要求 最小值 不大于 应被视为要求 最小值 参数不能大于单独传递的 一个。

    有时需要考虑的一个有用的模式是 ExposedHolder<T>

    class ExposedHolder<T>
    {
      public T Value;
      ExposedHolder() { }
      ExposedHolder(T val) { Value = T; }
    }
    

    如果一个人有 List<ExposedHolder<someStruct>> ,其中 someStruct 是一个变量聚合结构,可以执行如下操作 myList[3].Value.someField += 7; ,但是给予 myList[3].Value Value 而不是给它一个改变的方法。相比之下,如果使用 List<someStruct> var temp=myList[3]; temp.someField += 7; myList[3] = temp; . 如果使用可变类类型,则公开 myList[3] 到外部代码需要将所有字段复制到其他对象。如果使用不可变的类类型或“对象样式”结构,则需要构造一个新实例 我的列表[3] someField 这是不同的,然后将新实例存储到列表中。

    另一个注意事项:如果要存储大量类似的内容,最好将它们存储在可能嵌套的结构数组中,最好将每个数组的大小保持在1K到64K左右。结构数组是特殊的,在索引中可以直接引用内部的结构,因此可以说“a[12].x=5;”。尽管可以定义类似数组的对象,但C不允许它们与数组共享这种语法。

        8
  •  1
  •   Preet Sangha    14 年前

    使用类。

        9
  •  1
  •   Robert    14 年前

    从c++的角度来看,我同意修改structs属性比修改类慢。但我确实认为,由于结构是在堆栈上而不是堆上分配的,因此它们的读取速度会更快。从堆中读取数据需要比从堆栈中读取更多的检查。

        10
  •  1
  •   Daniel MoÅ¡mondor    14 年前

    好吧,如果你最终使用struct,那么去掉string并使用固定大小的char或byte缓冲区。

    那是表演。