0

like this:

    struct TheStruct
    {
        public int x;
    }
    public TheStruct CreateStruct()
    {
         //TheStruct xx = new TheStruct();
         TheStruct xx;

         xx.x = 100;

         return xx;
    }

when i use c# struct, i found that i can use it directly, or use new operator, it always works well. i don't know the difference about this. if struct can be only used on the stack, what's the background about :

TheStruct xx = new TheStruct()

where is the struct xx? on stack or on heap?

Soner Gönül
  • 97,193
  • 102
  • 206
  • 364
boo
  • 493
  • 6
  • 17

1 Answers1

2

Forget everything you know from C/C++. C# looks similar, but it is so different there's no point in carrying baggage over. Your question doesn't make sense.

Stack and heap are just an implementation detail on .NET - it might very well be allocated in a register for all you know.

Unlike C/C++, you can't choose where you allocate something. There's a few hints you have, but really, those are just implementation details. For example, no matter what you do, there's no working .NET runtime that will allow you to allocate a class on stack. The only thing preventing someone from making that runtime is deciding how to do that safely - the specification doesn't prohibit it.

Do not rely on implementation details like this, unless you really have to. Instead, think about the way you want to use the types. Do you want value semantics? Use value types. Reference semantics? Use reference types.

new simply calls the constructor of a given type. For structs, there's always a default constructor that simply zeroes out everything, and it's impossible to write your own constructor with no arguments (until C# 6, that is. Sadly.).

The code you have, of course, doesn't compile. You're using an unassigned variable. The same thing would work with a field, though. EDIT: As noted in the comments, it does compile, as long as you assign all the fields of the struct. In a way, you're creating your own struct constructor by doing that. Maybe it's a performance micro-optimization. I wouldn't use that syntax unless necessary - explicitly using new MyStruct() or default(MyStruct) is cleaner. Unless you can prove it makes a difference, I would simply use default or a constructor.

Right now, you can use new MyStruct() and default(MyStruct) interchangeably - both simply zero out the relevant memory (whether that's something that actually happens is an implementation detail, but you will have a value with all zeroes). In fact, that's how .NET works for all types - every piece of memory you allocate will always be zeroes as a default.

There's places where C# is very similar to C/C++. But memory allocation certainly isn't one of those places :)

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • Actually the code does in fact compile. The compiler actually tracks the fields in this case to know whether they have all been assigned before say the struct is passed to another method or returned. – Mike Zboray Apr 13 '15 at 07:37
  • @mikez Wow, what an ugly hack. Okay, let me fix that :D – Luaan Apr 13 '15 at 07:40
  • It's worth noting that executing the statement `StructType S = new StructType();` will clear all fields of `StructType`, but `StructType S = new StructType(someParams);` might not write any of them. Within the guts of the compiled code, a struct constructor is a function that accepts the struct as an `out` parameter, and an `out` parameter is merely a `ref` parameter that is tagged with an attribute that some languages ignore. If a struct constructor passes `this` as an `out` parameter to a virtual method overwrite written in a language other than C# and that method doesn't write to it... – supercat Apr 13 '15 at 20:52
  • ...the statement `StructType S = new StructType(someParams);` may not end up writing any of the fields in `S`, even though the compiler will think that it wrote all of them. – supercat Apr 13 '15 at 20:53
  • @supercat Possibly, but what observable difference does that make? The memory is still pre-zeroed, and if you see that the struct is not doing what you expect it to do, it's your expectations that are wrong. Either you'll use a different struct, or find out why it's the way it is and adjust accordingly. – Luaan Apr 14 '15 at 07:06
  • @Luaan: Probably the most important scenario would be if a struct constructor calls `IDictionary.TryGetValue()` for an `IDictionary` implementation written in a language other than C#. It's entirely possible that such a method may leave its byref parameter unaltered if a key isn't found (in some cases that's both faster and more useful than having it assign `default(TValue)`), in which case passing `structType myStruct = new structType(dictionaryKey);` a key which isn't in the dictionary may leave `myStruct` holding an unexpected value. – supercat Apr 14 '15 at 16:11
  • @Luaan: BTW, if the initialization appears in a loop the structure *may not be pre-zeroed after the first iteration*--that's my point. It's possible that on the second pass through the loop the structure will still hold data left over from the first pass. – supercat Apr 14 '15 at 19:29
  • @supercat That's an interesting scenario. I'm not going to test it, since it's a lot far fetched, but at least it would qualify as observable difference. If it's true. Can you reproduce an actual piece of code that would accomplish this? You could post that as a new self-answered question if it indeed shows how you can corrupt your stack. Unlikely scenario, but it might help someone with a difficult to debug bug :) – Luaan Apr 15 '15 at 07:47
  • @Luaan: It doesn't "corrupt the stack", and such a program would need to mix C# and VB.NET (though it's common for people to use libraries without knowing or caring what language they're written in, and C# isn't the only language used for writing libraries) so it would be a little awkward for readers to test, though I have in fact written and tested such code and it does behave as describe. Perhaps it may be worth writing up, since it is interesting. – supercat Apr 15 '15 at 14:38
  • @supercat I think that's pretty much the text-book definition of "corrupting the stack" - it doesn't have the data it's supposed to have as per the constraints given by the language. Sure, it's nowhere close to other forms of stack corruption (it's still a *valid* structure, and the memory is valid as well), but it's still a corruption. And of course, there's much easier ways to corrupt stack in .NET - native interop and unsafe code being pretty easy to use for that end. But that's pointless - I assume you do agree with me on the description, if not the name :D – Luaan Apr 15 '15 at 14:51
  • @Luaan: I reserve the term "stack corruption" for situations where something gets written to the stack that shouldn't. This scenario would be more accurately be described as untrapped use of semi-uninitialized storage (I say semi-uninitialized because I think .NET forces a variable to be initialized between the time it is first given to a value of a given type and the time that variable is first passed to outside code, though it does not force re-initialization within a loop). – supercat Apr 15 '15 at 15:17
  • @supercat Yeah, I'm not even saying .NET *should* force the re-initialization - that would be a significant performance penalty for very little benefit. And obviously, CLR specification doesn't even care about something like "stack", that's just the concrete implementation in MSCLR (and Mono). – Luaan Apr 15 '15 at 15:21