In the book Effective C++, I saw the passage below:
As a result, if you write
class Empty{};
it's essentially the same as if you'd written this:
class Empty { public: Empty() { ... } Empty(const Empty& rhs) { ... } ~Empty() { ... } Empty& operator=(const Empty& rhs) { ... } // copy assignment operator };
The following code will cause each function to be generated:
Empty e1; Empty e2(e1); e2 = e1;
But after disassembling the executable file which was created by compiling the code above, I realized it not the case: there isn't any function being invoked.
Here is the major assembly code:
00000000004006cd <main>:
4006cd: 55 push %rbp
4006ce: 48 89 e5 mov %rsp,%rbp
4006d1: b8 00 00 00 00 mov $0x0,%eax
4006d6: 5d pop %rbp
4006d7: c3 retq
There isn't any function named "Empty" in the .text
segment.
Then what indeed is the behaviour of a compiler after we call a constructor or assignment of an empty class? Does it generate some functions as the book said? If so, where are they stored?
A "noop" or "null function": var noop = function(){}
It's the copy =operator. Just like there is a copy constructor, there is a copy assignment operator.
C++ classes are often "empty," which means that their internal representation does not require any bits of memory at run time. This is the case typically for classes that contain only type members, nonvirtual function members, and static data members.
An empty class could be used as a "token" defining something unique; in certain patterns, you want an implementation-agnostic representation of a unique instance, which has no value to the developer other than its uniqueness.
Empty class: It is a class that does not contain any data members (e.g. int a, float b, char c, and string d, etc.) However, an empty class may contain member functions. Why actually an empty class in C++ takes one byte? Simply a class without an object requires no space allocated to it.
As a side note, in C++, an empty list means a function can only be called without any parameter. In C++, both void fun () and void fun (void) are same. The main function is a special function. Every C++ program must contain a function named main. It serves as the entry point for the program.
A function is a group of statements that together performs a task. All C programs are written using functions to improve re-usability and understandability. Here are some main advantages of Functions in C: We can call the C Functions many times. So there will be no need to write the same code again and again.
We can call the C Functions many times. So there will be no need to write the same code again and again. C Functions help in the optimization of the C Program because we don’t need to write much code. Declaration of C Function, tells the compiler about a function’s name, it’s the return type and the parameters.
The functions exist, but can be inlined.
When the compiler inlines the functions, it realizes they are no-ops, and there is no code generated.
What the book is saying, is true to an extent, the notional functions are created by the compiler, for inline and direct calling.
But the generated code is empty, so an optimizing compiler will then remove any evidence of the function (setting up a this pointer), and the functions will never be directly called.
The book is not really trying to explain the code generated, but the impact of creating a class, and the "hidden" functions it generates for normal operation.
Those methods are indeed generated for the class, but they are generated as "inline".
As they are member-by-member implementations (for example the copy constructor will copy-construct all members) when the class
is empty then nothing is actually done in them, and being inline they're just invisible.
It's very important to remember however that those methods get automatically an implementation... for example the code
struct Foo {
char *buf;
Foo() : buf(new char[10]) {}
~Foo() { delete[] buf; }
};
is buggy, because the automatically generated code for copy constructor and assignment is wrong and will lead to multiple deletion of the buffer.
It is buggy not because of something that has been written, but for something that has not been written and this is tricky. That's why is extremely important to remember what C++ will write automatically for you: if that implementation is what you want then perfect, but if not then fix it by providing the correct implementation or forbid the creation or use of that wrong code.
You and the book are coming at this situation from different levels of abstraction.
The book uses the term "generated" to refer to C++ functions being implicitly defined by the compiler into the abstract C++ program. This absolutely does happen.
You're interpreting it to mean actual generation of actual machine code in the translated program. That's not what it means. Generation of actual machine code is always subject to the compiler's whims, as long as the semantics of your original abstract program are maintained.
As such, the book is certainly not incorrect, though I would probably have used a different word in the interests of clarity. Sticking to standard terminology never hurts.
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