views:

304

answers:

6

Since structs are value-types, their data is copied when passed into a method as an argument. Example:

int someInt = 7;

DoSomeMethod(someInt); // <-- This is passing the "value" 7.

So far, easy to understand, and you're probably wondering how my question is valid... so consider the following:

public struct TimmysStructOfGoodness
{
    public int SomeInt1;
    public int SomeInt2;
    public int SomeInt3;
    // ... later that day ...
    public int SomeInt999;
}

and then, with reference to the following code:

TimmysStructOfGoodness someStructOfGoodness = new blah blah blah...

DoSomeMethod(someStructOfGoodness); // <-- **HERE IS WHERE THE QUESTION APPLIES!**

Does the above statement try to allocate several megs of ram to "copy" my value-type (struct)?

If the answer is yes - then when/where is the line between "faster" and "slower"?

If no - then why not? Because what I know of value-types, this should be a problem.

MAJOR DISCLAIMER: I know that this has nothing to do with why you would use a struct verses a class, and I know that I will never make a struct with 999 fields - this is just a question of underlying internals and guts and the like :)

A: 

In short term: Yes, struct are faster. In long details look: http://dotnetperls.com/struct-examples

Tuukka
+7  A: 

Structs and classes do not just have different performance, they behave differently too. You should use the one that is most suitable for the type you are implementing. Guidelines of when to use one or the other are clearly described on MSDN. Use a struct only if all the following apply:

  • It logically represents a single value, similar to primitive types (integer, double, and so on).
  • It has an instance size smaller than 16 bytes.
  • It is immutable.
  • It will not have to be boxed frequently.

If you are passing a struct to a function, you will get a copy of it. If your struct is large then it will result in copying a lot of data. A reference is typically implemented as 4 bytes (on x86) so passing an object requires only copying these 4 bytes.

Notice also that the above guidelines require that structs are small.

Mark Byers
-1. While the information is correct, he specifically stated that he was *not* talking about (nor interested in) the different use cases for struct vs. class.
Adam Robinson
Well stated, but see the comment above by Adam.
Timothy Khouri
It's worth poiting out: you can pass a struct by ref/out and it will not result in a copy. You can also box a struct onto the heap, in which case, again no copy. The way you use structs and pass them around impacts where they are allocated, and how they are copied. A struct that is declared a member of a class, for example, is also not allocated on the stack - but on the heap.
LBushkin
@LBushkin: If you box a struct, it *is* copied (at the time of boxing). Yes, passing around the `object` won't result in a deep copy, but boxing and unboxing are always copy operations.
Adam Robinson
@Adam Robinson: Sure, but the question is like asking "Which is faster, a relaxing stroll in the park, or driving to the cinema to see your favorite film?" You can time both to see which is faster, but since the two are not exactly interchangable the comparison doesn't necessarily make any sense. I think this is worth pointing out, if not for the poster, for other readers here.
Mark Byers
@Mark: True enough, but answering a question that wasn't asked isn't the solution to a faulty question.
Adam Robinson
+1  A: 

The answer to your question is: Yes. When you define a struct, each assignment incurs a copy operation.

There is not exact line which separates "fast" from "slow" because there are a lot of factors that affect speed WRT to structs, such as:

<correction> Structs are stored by value: on the stack or within the containing objects. Thus they promote cache locality as chances are higher that the relevant page is already loaded into CPU's cache where arbitrary heap pages are likely not to. </correction> Also, structs do not allow method overriding so method dispatch is also (marginally) faster.

On the other hand, each assignment incurs a copy. So if your code has a lot of assignments the advantages mentioned above will be outweighed by the cost of the copy operations. The break even point is different from one program to another (due to different characteristics of cache locality, method dispatching and assignments)

Itay
While I did upvote, this needs to be clarified/corrected. Only local structs will be declared on the stack; any instance or static structs, as with all other instance/static members, be declared on the heap.
Adam Robinson
Just to be clear, remember you can always pass the struct to the other method by reference, avoinding the copy if you don't need a copy.
Charles Bretana
@Adam: You're right. Corrected.
Itay
+4  A: 

(updated, thanks to contributions from other users)

Unlike class, struct is created on stack. So, it is faster to instantiate (and destroy) a struct than a class.

Unless (as Adam Robinson pointed out) struct is a class member in which case it is allocated in heap, along with everything else.

On the other hand, every time you assign a structure or pass it to a function, it gets copied.

I don't think there's a hard limit for a struct size. Thousands of bytes is definitely too much. MSDN says:

Unless you need reference type semantics, a class that is smaller than 16 bytes may be more efficiently handled by the system as a struct.

This is - if you need to pass it by reference make it a class, regardless of the size.

On the second thought, you can still pass struct by reference simply by specifying ref in the function parameter list.

So, a large struct can actually be ok if you pass it by reference and use as a class member.

yu_sha
Very nice quote (and informative)!
Timothy Khouri
This is not entirely accurate...local structs are declared on the stack; any instance variable (or static variable) will still be declared on the heap, just like any other instance or static member.
Adam Robinson
While there are a lot of good answers, this one is probably the "best" in that you've included the '16 bytes' reference from the MSDN - which is probably the closest thing to closure I can hope to find on this question.
Timothy Khouri
@Adam Robinson - yes, you are right.
yu_sha
Also, per Eric Lippert, "The stack is an implementation detail." http://blogs.msdn.com/ericlippert/archive/2009/04/27/the-stack-is-an-implementation-detail.aspx Not a language feature.
Craig Stuntz
Since the question was about the performance, we have to look into implementation detail. There's no such thing as language performance unless it's actually implemented.
yu_sha
+5  A: 

The performance implications of structs depend on exactly how you use such structs.

It's impossible to make a categorical statement about whether structs are faster or slower than reference types. It all depends on how you use them, and in what context.

Structs (value types in general) can end up allocated on either the stack or the heap - depending on their declaration context. If you declare it in the body of a method (and don't explicitly box it), the struct will end up on the stack. If you then pass that struct to a method that accepts it by value (as in you example), it will indeed be copied - but on the stack. Allocation on the stack is a very efficient process (BTW, the .NET heap is also very efficient) - but it is a copy process.

You can, of course, pass the struct using ref/out - in which case no copying will occur - a reference to the struct will be passed to the method. This may, or may not, be desirable - since it will allow the called method to change the contents of the struct.

A struct that is declared as a member of a class will actually be allocated on the heap (as part of the memory layout of the class). If you pass that class around, the struct will not be copied, but will still be accessible through the class reference.

You can also get a struct onto the heap by explicitly boxing it:

object x = new MyStruct( ... );  // boxed on the heap

Jon Skeet has a good article about where things end up in memory that you should read.

LBushkin
+2  A: 

To add to the confusion, remember, if you don't need a copy passed to the other method, you can always pass the struct by reference to avoid making a copy ...

Charles Bretana
ooh, good point :)
Timothy Khouri