Is there a way to actually see (output to file, console etc) implicit compiler generated or = default methods (in C++)?
(Target compilers: vc, clang, gcc)
I'd like to see how these functions are actually implemented. For example, how does the assignment operator assigns its values, does it check for self assignment, is const correctness given etc). I did not found any statisfying result on the www that actually shows the implementations of these compiler generated functions.
The semantics of the "special member" functions are defined by the C++ standard, in
section 12
In brief, they do what you think they do;
The default will invoke the defaults of the bases and the members
The copy will invoke the copy of the bases and members
The same applies for the moves, assignments and destructor
If, for some reason, one of them would violate a const correctness or the corresponding constructor or assignment of the base or members is not available, or some other issue arrises, then that special member is not declared.
An an additional note; there are specific rules that apply to the defaults if one (or some) of the special members are defined by the user (detailed here).
Related
I am rereading Scott Meyers’ Effective C++ after a hiatus of 16 years. Although I have not read the latest C++ standard, but it has come to my attention that C++ has changed since the second edition of Effective C++ was written.
In the third edition of his book, Scott Meyers has mentioned that even if you have an empty class, meaning there is nothing to initialize or assign, a C++ compiler will still generate at least 3 default functions, namely, default constructor, default copy constructor, assignment operator, and probably some other functions. According to Mr. Meyers, the following code will result in the generation of the aforementioned functions.
class Empty {}
Empty E1; // Default constructor.
Empty E2 ( E1 ); // Default copy constructor.
E1 = E2; // Default assignment operator.
Considering that there really is nothing to initialize, as the class is empty, does the C++ still generate some sort of code for the stated functions?
probably some other functions.
Yes, the move constructor and the move assignment operator. That's it.
Considering that there really is nothing to initialize, as the class is empty, does the C++ still generate some sort of code for the stated functions?
Sometimes. What happens is that those special members are declared, but not defined. They are only defined when they are used (i.e. odr-used or constant evaluated), otherwise, there is no code generated for them as they aren't defined.
And because you have an empty class, if the special members are defined, they will do nothing at all.
Sometimes, users implement functions with the equivalent functionality as their implicitly defined versions. For example, a copy constructor which simply calls the copy constructor of all its members.
struct A
{
int B;
A(const A& a) : B(a.B) { }
}
This is undesirable, because it causes additional maintenance, for example if the class members are renamed/reordered, etc., and reduces readability. Also, adding these functions also means that functions such as std::is_trivially_copy_constructable claim the type is cannot be trivially copy constructed (but in practice, it actually could be).
I have a code base where this seems to be a common occurrence, which I would like to rectify, by deleting these implementations. However, I am uneasy about removing functionality that seems to be identical to implicit implementation, in case it might not actually be equivalent. Is there a method for determining whether a function is equivalent to its implicit version? (Using any toolset/language variation/etc is acceptable).
My suggestion is to not try to programmatically determine if these functions are the same as the default implementation, because the difference might actually be a mistake (and they were supposed to have the normal default behavior).
Instead I would just suggest to write up a set of unit tests that take care of testing the expected behavior of the various functions, and then make sure they pass on the default implementations. Then not only do you have a test framework for future enhancements you can be confident the functions did what you wanted.
Are C++ standard library implementations allowed to add public (and protected) members to standard types' interfaces? N3797 17.6.5.5 [member.functions]/2 says:
An implementation may declare additional non-virtual member function signatures within a class:
— by adding arguments with default values to a member function signature; [ Note: An implementation may not add arguments with default values to virtual, global, or non-member functions. — end note ]
— by replacing a member function signature with default values by two or more member function signatures with equivalent behavior; and
— by adding a member function signature for a member function name.
Does this mean that a standard library cannot add any additional public members with names not mentioned in the standard under any circumstances (that include, for example, reserved identifiers)?
A tiny bit of explanation: this is the text about adding signatures (which I assume talks about new signatures just for functions that are already defined to be there, so no new names) I managed to find in the standard. There is also the footnote 189, which says:
A valid C++ program always calls the expected library member function, or one with equivalent behavior. An implementation may also define additional member functions that would otherwise not be called by a valid C++ program.
All this text originates from [member.functions], so it is clearly about member functions only. My question is more generic and asks for any references I could've missed: is a standard library implementation allowed to add new names to public (and/or protected) interfaces of a standard type, be it data or function members?
I believe you have what you need with a combination of foot note 189 which says:
A valid C++ program always calls the expected library member function, or one with equivalent behavior. An implementation may also define additional member functions that would otherwise not be called by a valid C++ program.
and section 17.6.5.11 Derived classes which says:
An implementation may derive any class in the C++ standard library from a class with a name reserved to the implementation.
but does not add any restrictions, i.e. it does not let's say restrict the access qualifiers etc...
and we can see libstdc++ uses derived classes pretty effectively, for example in stl_vector.h. Although as far as I can see libstdc++ does seem to eschew adding public data members but that is probably more for clean design.
At minimum, this looks under-specified but if you stick to something similar to libstdc++ implementation style you should be good.
I think that the key to reading footnote 189 is the phrase would otherwise not be called by a valid C++ program.
Remember that identifiers beginning with an underscore followed by a capital letter (or containing two consecutive underscores anywhere) are reserved for the implementation. (section 17.6.4.3.2)
So implementations are free to add public/protected member functions that are named in that manner.
For example, in libc++, std::vector has a protected member function named __throw_length_error
In "The C++ programming language", at page 265, the author makes the following statement:
Because of historical accident, the operators = (assignment), & (address-of), and , (sequencing;
§6.2.2) have predefined meanings when applied to class objects. These predefined meanings can
be made inaccessible to general users by making them private:
Then the following example is given:
class X {
private:
void operator=(const X&);
void operator&();
void operator,(const X&);
// ...
};
void f(X a, X b)
{
a = b; // error: operator= private
&a; // error: operator& private
a,b; // error: operator, private
}
I can't quite understand what do these "error" comments refer to? Does that mean I should not define a function like f, or that all of the =, &, and , operators should be used according to the default way, and it is not necessary to redefine them?
This example simply shows a way to prevent yourself or other developers of the code from using operators, which can be used without having been defined in the class, because they're automatically generated (and have default meanings for the operations they represent).
The author of the example meant, that if you try to assign b to a (in line a = b) it will cause an error, because the assignment operator is private in the class definition.
Similar error occurs in case of address-of in the second line, and the comma operator in the third.
Making default operators/constructors private if you know they're not supposed to be used (or haven't been implemented yet) is good, because one may accidentally use a very frequent operator like assignment or copy-constructor, being unaware that it's default behavior conflicts with the class lifecycle. If such operator or constructor is made private at the very beginning of class design, the compiler will generate a compile-time error instead of performing a potentially dangerous operation without notice if the programmer accidentally uses the method.
Think default assignment operator and member pointer: it will copy the pointer whereas you might want the object to be the owner of data. Then, after someone assigns one object to another without knowing that assignment is not implemented, you will end up with a double free error. Instead of that, if the operator is private, you'll get a nice error and the code will not even compile, and you'll know what's going on.
The author intends to point out here that the operators =, & and , are usually implicitly available for a class.
So if you don't want your objects to be operated on through them then you declare them as private thus disallowing their use.
Since they are declared as private you cannot access them anymore outside the class and the compiler gives you a compilation error. The function is an example showing that.
Providing your own implementation of any operator is basically the same as implementing a class method. Operators and methods are the same in terms of accessibility. What you do is disallowing access to operators from the caller's code.
It's absolutely the same as if you defined a private method and then tried to call it from some code that is not part of your class. Just make the operators public and errors will go away.
It basically prevents any one from making an 'X' object and using the "=", "&", and "," operators on that class. Because the author of the class may implement those objects with a meaning that is quite different to what the consumer of the class might think they do ... so its best to prevent them being used at all in the case of ambiguity.
The function f is an example of a user trying to use the private operators. It shows you what code it is that you're preventing by making them private. The comment // error means that a program that contained that line would fail to compile for the stated reason.
Before discussing the error, a key here is to understand that these operations will be implicitly made available for your class. This is the essence of Scott Meyers' advice "Know what functions C++ silently writes and calls."
C++ will automatically implement the assignment operator for your class, but it may not be done correctly (for example, if your class contains a pointer member variable). By defining the assignment operator explicitly, you are telling the compiler to use your implementation instead of generating one for you. And by making it private, you are essentially disallowing assignment of one class instance to another. Anywhere you try to do this in your code, the compiler will complain, which is a good thing if you really don't want assignment to be done.
In function f the author is showing you that these statements will not compile because of how the operators are defined in the class. It is perfectly acceptable to redefine operators for your class, and sometimes it is definitely required (for example, to implement a deep copy of a pointer member variable in your class). The point of the example is to show that a) you can provide your own implementation of these operators for your class, and b) because of this you have control over whether the operators are supported and implemented correctly for your class.
To disallow copying or assigning a class it's common practice to make the copy constructor
and assignment operator private. Both Google and Qt have macros to make this easy and visible.
These macros are:
Google:
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
Qt:
#define Q_DISABLE_COPY(Class) \
Class(const Class &); \
Class &operator=(const Class &);
Questions:
Why are the signatures of the two assignment operators different? It seems like the Qt version is correct.
What is the practical difference between the two?
It doesn't matter. The return type is not part of a function's signature, as it does not participate in overload resolution. So when you attempt to perform an assignment, both declarations will match, regardless of whether you use the return type.
And since the entire point in these macros is that the functions will never get called, it doesn't matter that one returns void.
I'd just like to mention that there is an alternative strategy for implementing an abstraction for disallowing copy and assignment of a class. The idea is to use inheritance instead of the preprocessor. I personally prefer this approach as I follow the rule of thumb that it is best to avoid using the preprocessor when at all possible.
boost::noncopyable is an example implementation. It is used as follows:
class A : noncopyable
{
...
};
See Boost.Utility, specifically boost::noncopyable. It's not a macro but a base class with private copy and assignment. It prevents the compiler from generating implicit copy and assignment in derived classes.
edit: Sorry, this was not an answer to the original question. By the way, boost::noncopyable uses a const reference as return type for the assignment operator. I was under the impression that the type of the return value doesn't matter since it's not supposed to be used. Still, making the operator private doesn't prevent usage inside the class or friends in which case a non-usual return type (like void, a const reference, etc) might lead to compilation errors and catch additional bugs.
There's no practical difference. The assignment operator signatures differ just as a matter of style. It's usual to have an assignment operator returning a reference to allow chaining:
a = b = c;
but a version returning void is also legal and will work just fine for cases when the only purpose is to just declare the operator private and therefore prohibited to use.
From the standard, 12.8, clause 9: "A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X, X&, const X&, volatile X&, or const volatile X&." It says nothing about the return type, so any return type is permissible.
Clause 10 says "If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly."
Therefore, declaring any X::operator=(const X&) (or any other of the specified assignment types) is sufficient. Neither the body nor the return type is significant if the operator will never be used.
Therefore, it's a stylistic difference, with one macro doing what we'd likely expect and one saving a few characters and doing the job in a way that's likely to surprise some people. I think the Qt macro is better stylistically. Since we're talking macro, we're not talking about the programmer having to type anything extra, and failing to surprise people is a good thing in a language construct.
Others have already answered why it's legal to have different return values for operator=; IMHO jalf said it best.
However, you might wonder why Google uses a different return type, and I suspect it's this:
You don't have to repeat the type name when disabling the assignment operator like this. Usually the type name is the longest part of the declaration.
Of course, this reason is void given that a macro is used but still - old habits die hard. :-)
Both serve the same purpose
Once you write this one:
Class &operator=(const Class &);
you will get the benefits of chain assignments. But in this case you want the assignment operator to be private. so it doesn't matter.
Qt version is backward compatible, while google's is not.
If you develop your library and deprecate the use of assignment before you completely remove it, in Qt it will most likely retain the signature it originally had. In this case older application will continue to run with new version of library (however, they won't compile with the newer version).
Google's macro doesn't have such a property.
As several other answers have mentioned, the return type of the function doesn't participate in the function signature, so both declarations are equivalent as far as making the assignment operator unusable by clients of the class.
Personally I prefer the idiom of having a class privately inherit from an empty non-copyable base class (like boost::noncopyable, but I have my own so I can use it in projects that don't have boost available). The empty base class optimization takes care of making sure there's zero overhead, and it's simple, readable, and doesn't rely on the dreaded preprocessor macro functionality.
It also has the advantage that copy and assignment can't even be used within class implementation code - it'll fail at compile time while these macros will fail at link time (likely with a less informative error message).
Incidentally, if you have access to the Boost libraries (You don't? Why the heck not??), The Utility library has had the noncopyable class for a long time:
class YourNonCopyableClass : boost::noncopyable {
Clearer IMHO.
In practice I would say that both should not be used anymore if you have a C++11 compiler.
You should instead use the delete feature , see here
Meaning of = delete after function declaration
and here
http://www.stroustrup.com/C++11FAQ.html#default
Why : essentially because compiler message is much more clearer. When the compiler need one of the copy or copy assignment operator, it immediately points out to the line where the =delete was coded.
Better and complete explanations can also be found in Item 11: Prefer deleted functions to private undefined ones from Effective Modern C++ book by Scott Meyers