21

Is there a specific reason that this would break the language conceptually or a specific reason that this is technically infeasible in some cases?

The usage would be with new operator.

Edit: I'm going to give up hope on getting my "new operator" and "operator new" straight and be direct.

The point of the question is: why are constructors special? Keep in mind of course that language specifications tell us what is legal, but not necessarily moral. What is legal is typically informed by what is logically consistent with the rest of the language, what is simple and concise, and what is feasible for compilers to implement. The possible rationale of the standards committee in weighing these factors are deliberate and interesting -- hence the question.

17
  • It would not be problem of taking address of a constructor, but being able to pass around type. Templates can do that.
    – Euphoric
    Commented Jun 20, 2014 at 19:33
  • What if you have a function template that you want to construct an object using a constructor that will be specified as an argument to the function? Commented Jun 20, 2014 at 19:37
  • 1
    There will be alternatives for any example I can think up, but still, why should constructors be special? There are plenty of things that you likely won't use in most programming languages but special cases like this usually come with a justification. Commented Jun 20, 2014 at 19:47
  • 1
    @RobertHarvey The question occurred to me when I was about to type up a factory class. Commented Jun 20, 2014 at 21:05
  • 1
    I wonder if the C++11 std::make_unique and std::make_shared can adequately solve the underlying practical motivation for this question. These are template methods, which means one need to capture the input arguments to the constructor, and then forward them to the actual constructor.
    – rwong
    Commented Sep 9, 2016 at 4:49

4 Answers 4

13

Pointers-to-member functions make only sense if you have more than one member function with the same signature - otherwise there would be only one possible value for your pointer. But that is not possible for contructors, since in C++ different constructors of the same class must have different signatures.

The alternative for Stroustrup would have been to choose a syntax for C++ where constructors could have a name different from the class name - but that would have prevented some very elegant aspects of the existing ctor syntax and had made the language more complicated. For me that looks like a high price just to allow a seldom needed feature which can be easily simulated by "outsourcing" the initialization of an object from the ctor to a different init function (a normal member function for which pointer-to-members can be created).

7
  • 2
    Still, why prevent memcpy(buffer, (&std::string)(int, char), size)? (Probably extremely un-kosher, but this is C++ after all.) Commented Jun 21, 2014 at 9:19
  • 4
    sorry, but what you wrote makes no sense. I see nothing wrong with having pointer to member pointing to a constructor. also, it Sounds like you quoted something, without link to source. Commented Jun 21, 2014 at 9:23
  • 1
    @ThomasEding: what exactly do you expect that statement to do? Copying the assembly code of the string ctor somewgere? How will "size" be determined (even if you try something equivalent for a standard member function)?
    – Doc Brown
    Commented Jun 21, 2014 at 9:35
  • I'd expect it do the same thing it would do as given the address of a free function pointer memcpy(buffer, strlen, size). Presumably it would copy the assembly, but who knows. Whether or not it the code could be invoked without crashing would require knowledge about the compiler you use. Same goes for determining size. It would be highly platform dependent, but lots of non-portable C++ constructs are used in production code. I see no reason to outlaw it. Commented Jun 21, 2014 at 10:07
  • @ThomasEding: A conforming C++ compiler is expected to give a diagnostic when trying to access a function pointer as if it were a data pointer. A non-conforming C++ compiler could do anything, but they can also provide a non-c++ way of accessing a constructor as well. That is not a reason to add a feature to C++ that has no uses in conforming code. Commented Jun 21, 2014 at 16:17
8

A constructor is a function that you call when the object does not yet exist, so it could not be a member function. It could be static.

A constructor actually gets called with a this pointer, after the memory has been allocated but before it has been completely initialised. As a consequence a constructor has a number of privileged features.

If you had a pointer to a constructor it would either have to be a static pointer, something like a factory function, or a special pointer to something that would be called immediately after memory allocation. It could not be an ordinary member function and still work as a constructor.

The only useful purpose that comes to mind is a special kind of pointer that could be passed to the new operator to allow it to indirect on which constructor to use. I guess that could be handy, but it would require significant new syntax and presumably the answer is: they thought about it and it wasn't worth the effort.

If you just want to refactor out common initialisation code then an ordinary memory function is usually a sufficient answer, and you can get a pointer to one of those.

10
  • This seems like the most correct answer. I recall an article from many (many) years ago concerning operator new and the internal workings of “the new operator”. operator new() allocates space. The new operator calls the constructor with that allocated space. Taking the address of a constructor is “special” because calling the constructor requires space. The access for calling a constructor like this is with the placement new.
    – Bill Door
    Commented Jun 21, 2014 at 17:11
  • 1
    The word "exist" obscures the detail that an object can have an address and have allocated memory but not be initialized. On member function or not, I think getting the this pointer makes a function a member function because it's clearly associated with an object instance (even if uninitialized). That said, the answer raises a good point: the constructor is the only member function that can be called on an uninitialized object. Commented Jun 21, 2014 at 21:31
  • 1
    And 12.1: "A constructor shall not be virtual (10.3) or static (9.4)." (my emphasis) Commented Jun 21, 2014 at 22:12
  • 1
    The fact is that if you compile with debug symbols and look for a stack trace, there is actually a pointer to the constructor. What I was never able is to find the syntax to get this pointer (&A::A doesn't work in any of the compilers I tried.)
    – alfC
    Commented May 5, 2016 at 8:37
  • 1
    @Praxeolitic: in your example, the object is fully initialised before init() is called. Base classes have been called, member initialisation is complete. the contents of init() are equivalent to statements within the constructor.
    – david.pfx
    Commented Sep 11, 2016 at 0:39
-3

This is because their is no return type of constructor and you are not reserving any space for the constructor in memory. Like u do in case of variable during declaration. For example : if u write simple variable X Then compiler will generate error because compiler will not understand the meaning of this. But when you write Int x; Then compiler come to know that it int type data variable , so it will reserved some space for variable.

Conclusion:- so the conclusion is that due to exclusion of return type it will not get the address in memory.

4
  • 1
    The code in the constructor has to have an address in memory because it has to be somewhere. There's no need to reserve space for it on the stack but it must be somewhere in memory. You can take the address of functions that don't return values. (void)(*fptr)() declares a pointer to a function with no return value. Commented Oct 10, 2015 at 10:22
  • 2
    You missed the point of the question - the original post asked about taking the address of the code for the constructor, not the result that the constructor provided. In addition, on this board, please use full words: "u" is not an acceptable replacement for "you". Commented Oct 10, 2015 at 12:20
  • Mr praxeolitic, I think if we don't mention any return type then compiler will not set a particular memory location for ctor and it location is set internally.... Can we fetch the address of any thing in c++ which is not given by compiler? If am wrong then please correct me with correct answer Commented Jun 7, 2016 at 18:21
  • And also tell me about reference variable. Can we fetch the address of reference variable? If no then what address printf("%u",&(&(j))); is printing if &j=x where x=10? Because address printed by printf and address of x are not same Commented Jun 7, 2016 at 18:34
-4

I'll take a wild guess:

C++ constructor and destructor are not functions at all: they are macros. They get inlined into the scope where the object is created, and the scope where the object is destroyed. In turn, there is no constructor nor destructor, the object just IS.

Actually, I think the other functions in the class are not functions neither, but inline functions that DONT get inlined because you take address of them(the compiler realizes you're onto it and doesn't inline or inlines the code into the function and optimizes that function) and in turn the function seems to "still be there", even though it would not if you haven't took address of it.

The virtual table of the C++ "object" is not like a JavaScript object, where you can get its' constructor and create objects from it at runtime via new XMLHttpRequest.constructor, but rather a collection of pointers to anonymous functions that act as means to interface with this object, excluding ability to create the object. And it doesn't even make sense to "delete" the object, because it's like trying to delete a struct, you can't: it's just a stack label, just write to it as you please under another label: you are free to use a class as 4 integers:

/* i imagine this string gets compiled into a struct, one of which's members happens to be a const char * which is initialized to exactly your string: no function calls are made during construction. */
std::string a = "hello, world";
int *myInt = (int *)(*((void **)&a));
myInt[0] = 3;
myInt[1] = 9;
myInt[2] = 20;
myInt[3] = 300;

There is no memory leak, there is no issues, except you effectively wasted a bunch of stack space that's reserved for the object interfacing and the string, but it's not going to destroy your program(as long as you don't try to use it as a string ever again).

Actually, the if my earlier assumptions are correct: the complete cost of the string is just the cost of storing these 32 bytes and the constant string space: the functions are only used at compile time, and may as well get inlined and tossed away after the object is created and used(As if you were working with a struct and only referred to it directly without any function calls, sure there's duplicate calls instead of function jumps, but this is usually faster and uses less space). In essence, whenever you call any function, compiler just replaces that call with the instructions to literally do it, with exceptions that the language designers have set.

Summary: C++ objects have no idea what they are; all the tools for interfacing with them are inlined statically, and lost at runtime. This makes working with classes as efficient as filling structs with data, and directly working with that data without calling any functions at all(these functions are inlined).

This is completely different from the approaches of COM/ObjectiveC as well as javascript, which retain the type information dynamically, at the cost of runtime overhead, memory management, calls of constructions, as the compiler can't throw this information away: it's necessary for dynamic dispatch. This in turn gives us the ability to "Talk" to our program at runtime, and develop it while it is running by having reflectable components.

9
  • 2
    sorry, but some parts of this "answer" are either wrong or dangerously misleading. Sadly, the comment space is far too small to list them all (most methods won't get inlined, this would prevent virtual dispatch and bloat the binary; even if inlined, there might be an addressable copy somewhere accessible; irrelevant code example that in the worst case corrupts your stack and in the best case doesn't fit your assumptions; ...)
    – hoffmale
    Commented Sep 9, 2016 at 3:18
  • The answer is naive, I just wanted to express my guess as to why constructor/destructor cannot be referenced. I agree that in the case of virtual classes, the vtable must persist, and addressable code must be in memory so that the vtable can reference it. However, classes that do not implement a virtual class, seem to be inlined, as in the case of std::string. Not everything gets inlined, but things that do not seem to be minimally put into an "anonymous" code block somewhere in memory. Also, how does the code corrupt the stack? Sure we lost the string, but otherwise all we did is reinterpret.
    – Dmytro
    Commented Sep 9, 2016 at 4:15
  • Memory corruption occurs in a computer program when the contents of a memory location are unintentionally modified. This program does it intentionally and does not try to use that string anymore, so there is no corruption, just wasted stack space. But yes, string's invariant is no longer maintained, it does clutter the scope(at the end of which, the stack is recovered).
    – Dmytro
    Commented Sep 9, 2016 at 4:19
  • depending on the string implementation you might write over bytes you don't want to. If string is something like struct { int size; const char * data; }; (like you seem to assume) you write 4 * 4 Bytes = 16 bytes on a memory address where you only reserved 8 bytes on a x86 machine, so 8 bytes are written over other data (which can corrupt your stack). Fortunately, std::string normally has some in-place optimisation for short strings, so it should be large enough for your example when using some major std implementation.
    – hoffmale
    Commented Sep 9, 2016 at 5:23
  • @hoffmale you are absolutely right, it could be 4 bytes it could be 8, or even 1 byte. However once you know the size of the string, you also know that that memory is on stack in the current scope, and you can use it as you please. My point was that if you do know the structure, it is packed in a way independant of any information about the class, unlike COM objects that have a uuid identifying their class as part of IUnknown's vtable. In turn, the compiler accesses this data directly via inlining, or mangled static functions.
    – Dmytro
    Commented Sep 9, 2016 at 5:26

Not the answer you're looking for? Browse other questions tagged or ask your own question.