14

I know about compiler-generated functions, the rule of three and the rule of five. In real-world scenarios, it may not be trivial to figure out exactly which of the compiler-generated functions (constructors, assignment operators, destructor) were actually created by the compiler.

Is there any way to list the compiler-generated functions for a specific class?

I am primarily interested in Visual Studio 2019 and Xcode, but a generic solution would be even more welcome.

sepp2k
  • 363,768
  • 54
  • 674
  • 675
Helge Klein
  • 8,829
  • 8
  • 51
  • 71

3 Answers3

15

The rules are complicated. I will steal from another answer which quotes a table from Howard Hinnant's presentation.

enter image description here

The moral here is that a good practice is to not rely on compiler implicit declares and explicitly declare every special member (as defaulted or deleted, depending on your needs)

bolov
  • 72,283
  • 15
  • 145
  • 224
  • If you explicitly declare every special member you lose "not declared" special members status for move constructor and assignment operator. – Maxim Egorushkin Jan 06 '20 at 17:39
  • @MaximEgorushkin my point is to declare them defaulted if you need them (although default can still mean not declared) or deleted if you don't want them. – bolov Jan 06 '20 at 17:54
  • Once you declare them they are no longer "not declared". – Maxim Egorushkin Jan 06 '20 at 18:22
  • @MaximEgorushkin you are right, I meant deleted. For instance if you have a `unique_ptr` member and you declare the copy assign `default` it will be deleted because of that member. That's what I meant. – bolov Jan 06 '20 at 18:31
  • 2
    @bolov The chart is useful but this does not answer my question. I want to find out which functions were actually generated by the compiler. In other words: I am not asking about what should happen in theory, but what is happening in practice. – Helge Klein Jan 06 '20 at 18:32
  • And that deleted member triggers a compiler error where "non declared" member wouldn't. That forces you to actually implement manually that member instead of writing "= default". "Non declared" is different from default and deleted, you may like to re-watch the talk you are quoting the picture from. – Maxim Egorushkin Jan 06 '20 at 18:39
  • @HelgeKlein, if "in practice" the compiler generates anything other than what should be generated "in theory" then the compiler is incorrect and there is a bug in the compiler. – tjwrona1992 Jan 06 '20 at 20:09
  • 1
    @tjwrona1992: By that argument, we would never need to test our code, because we'd know that if the compiler did anything different than we intended then there must be a bug in it. – ruakh Jan 07 '20 at 03:22
  • @ruakh if you don't trust your compiler to do what it is supposed to do how can you trust the testing tools to do what they are supposed to do? – bolov Jan 07 '20 at 14:58
  • @bolov: I do trust my compiler to do what it's supposed to do, but I don't trust *myself* to 100% reliably identify what my compiler's supposed to do in a given case, especially since a small typo can have massive semantic implications. (Though I guess that's why I don't usually use C++. C++ programmers do have to trust themselves to be perfect, despite all evidence to the contrary, because you can't test for UB . . .) – ruakh Jan 07 '20 at 17:30
  • @ruakh, Compilers are generally very heavily tested, you should be able to trust that your compiler will generate exactly what is documented in the C++ standard and nothing more/nothing less. If you can't trust your compiler to do that, then you should find a new compiler. What you can't trust is whether the input you give the compiler is correct, and that's why having tests for your own code is so important. – tjwrona1992 Jan 08 '20 at 21:13
  • In other words, you don't need tests to verify that the compiler is correct. You need tests to verify that you provided the compiler with the correct input. So testing is still very much required. – tjwrona1992 Jan 08 '20 at 21:15
  • 1
    @tjwrona1992: Yes, exactly. Likewise, the point of seeing what your compiler has generated is not to verify that the compiler is correct, but rather, to verify that you provided the compiler with the correct input. – ruakh Jan 08 '20 at 23:04
7

"Is there any way to list the compiler-generated functions for a specific class?"

Of course there is. On Linux (and other Unix systems) you can use nm, readelf and objdump on the generated object files/libraries/executable to disassemble them and inspect any exported symbols (and much more).

There are similar tools on Windows, I know, but that's not a platform I work much with, so unfortunately I cannot name exact tool names there.

Jesper Juhl
  • 30,449
  • 3
  • 47
  • 70
  • 1
    Although these tools may very well not show you what functions _might_ have been generated (i.e., the compiler was allowed to generate them, but you never used those functions so it decided to not bother, or link-time code elimination got rid of them) – JMAA Jan 06 '20 at 17:24
  • @JMAA In most cases, "allowed to generate but never used" would in Standard terms mean that a function was "implicitly declared" but was not "implicitly defined". Yes, this still means you won't see the symbols, even if inlining is disabled. – aschepler Jan 06 '20 at 17:28
  • 1
    Strictly speaking, this answer does more precisely responds to the question asked: "Which methods did the compiler generate?" That is not the same as the much less precise question "Which methods might have been generated by the compiler in a different context?" – rici Jan 06 '20 at 19:31
  • @rici True. But the more precise question is not easily answerable, so I went for what could be answered. Feel free to downvote if you think my answer is not valuable. – Jesper Juhl Jan 06 '20 at 19:35
  • 1
    @jesper: no, i already upvoted. I think the question you answered is more precise, as I said. The other question, which might have been the intent, requires some handwaving because it's contrafactual: we don't know what hypothetical contexts it might include. But this is the question literally asked, intentionally or not, so kudos for answering it. – rici Jan 06 '20 at 19:39
  • @ric: The question is asking about the *compiler*. This answer is only based on what the *linker* left. So no, this doesn't answer the question. – IInspectable Jan 11 '20 at 18:21
  • @IInspectable: ELF is the format of the *compiler*'s output (on Linux). So if you invoke `gcc -c` you get an ELF-format file, which you can pass through the various utilities mentioned in this answer. The linker doesn't come into it. – rici Jan 11 '20 at 18:24
  • @ric: This is straight from this answer: *"you can use nm, readelf and objdump on the generated object files/libraries/executable"*. – IInspectable Jan 11 '20 at 18:28
  • @IInspectable: That's right. The generated **object file** is what the compiler produces. Object files are the input to the linker, which produces an executable. So you can *also* use those utilities on linker output, but you can specifically use them on compiler output. (Or on the output of an *archiver* which combines several object files into a library.) – rici Jan 11 '20 at 18:33
  • @ric: Did you not read *"executable"* in the answer? Run them tools on the executable, and you do not get the answer to the question that was asked. – IInspectable Jan 11 '20 at 18:39
  • @Iinspectable: Yes, but it provides a list of possible things you can run those tools on. That is, I'm reading "object files/libraries/executable" as "object files *or* libraries *or* executable", because that's the only reading which makes sense. Those three terms are not aliases or synonyms for each other. – rici Jan 11 '20 at 18:41
  • @ric: Sure, but why mention *"executables"* when the question **explicitly** asks about the compiler? – IInspectable Jan 11 '20 at 18:48
  • @IInspectable: it doesn't invalidate an answer to also provide extra related information beyond what was requested. On the contrary, it makes the question and answer more useful for future readers with similar but not identical questions. – rici Jan 11 '20 at 18:53
1

This is currently only a partial answer.

Visual Studio 2019

Constructors

When defining a class object, Visual Studio's IntelliSense function shows the available constructors, both compiler-generated and your own:

enter image description here

This information does not always come up, unfortunately. To get it to work for the screenshot above, I had to type something in the parentheses, hence the comma.

Helge Klein
  • 8,829
  • 8
  • 51
  • 71