Given an empty constructor such as:
internal C()
{
}
Is it called upon object creation? It should only contain a return operation, so in theory, it could be discarded, right?
Note: It is clear to me, that for each class, an implicit constructor exists. The intend of this question is however; if the CLR calls constructors with exclusively a return
operation.
A constructor is always called on object instantiation, even if it's parameterless and empty. If you don't write any constructor, a default one is implicitly generated for you by the compiler.
This is to give you the possibility to write a constructor later on, without having to recompile any calling code.
Object instantiation always calls a constructor for this reason, except for edge cases like FormatterServices.GetUninitializedObject
which is the only way I know of to instantiate an object without calling a constructor (it's used for serialization purposes).
By the way, the newobj
IL opcode (which is used to instantiate a new object), explicitly takes a constructor as an input parameter:
The
newobj
instruction creates a new object or a new instance of a value type. Ctor is a metadata token (a methodref or methoddef that must be marked as a constructor) that indicates the name, class and signature of the constructor to call.The
newobj
instruction allocates a new instance of the class associated with ctor and initializes all the fields in the new instance to0
(of the proper type) or null references as appropriate. It then calls the constructor ctor with the given arguments along with the newly created instance. After the constructor has been called, the now initialized object reference (type O) is pushed on the stack.
So the type to create is actually identified by the constructor to call, not by the type token itself, which makes a constructor mandatory.
Since you want to know what the JIT does, here's the disassembly of the following line in Release mode (SomeClass
is a class with an empty default constructor):
var inst = new SomeClass();
x64:
000007FE95A30093 in al,dx
000007FE95A30094 and byte ptr [rax-73h],cl
000007FE95A30097 or eax,0FFEE4014h
000007FE95A3009C call 000007FEF5062400
000007FE95A300A1 mov rbx,rax
000007FE95A300A4 call 000007FEEC977A00
x86:
00320050 push ebp
00320051 mov ebp,esp
00320053 push esi
00320054 mov ecx,28380Ch
00320059 call 002720D4
0032005E mov esi,eax
00320060 call 72EA2578
00320065 mov ecx,eax
00320067 mov eax,dword ptr [ecx]
00320069 mov eax,dword ptr [eax+2Ch]
0032006C call dword ptr [eax+1Ch]
Ok, I'm not really fluent with assembly code, but the x64 version performs two calls. I suppose the first one is the allocation and the second one is the constructor call, but I'm not sure about that (VS won't let me go to these addresses for some reason). That third (indirected) call
in the x86 code is a surprise to me, I don't know what it's for.
No, the constructor should not be discarded because it's seems like the author of the class intended it to be instantiated only from within its declaring assembly (by marking the constructor as internal
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With