Does access control matter for deleted constructors? - c++

Is there a difference in behavior between whether an explicitly deleted constructor is public, protected or private?
For example, a non copyable class would have a deleted copy constructor (and deleted copy assignment). The constructor would not be available to neither subclasses (or friends) nor to outside users of the class, because it doesn't exist, regardless of its access control.
The only difference I see would be in what manner different scopes would see that the copy constructor doesn't exist - whether it is just not there (as far as that scope knows) or it is explicitly deleted.
Now, it might be beneficial to have the best formal interface for the class - that is, if everyone should know that the class is non-copyable, it should be publicly deleted. Compiler error messages might also be more informative. But other than that - would there be any actual observable difference in the class behavior? That is, something one could do with a class which has its deleted constructor with access X which he couldn't do if that constructor had access Y?

Since it's overload resolution that makes the program ill-formed in this case, and not access specifiers (which are checked later), there is no difference in outcome. The compiler will always complain that a deleted function was picked.
But since the idiom before C++11 was "declare but not define a private copy c'tor to disable copying", I would consider it going along with the same idiom, and therefore favorable. You are using the "old slang" with some new language to describe the same thing, except better.

Related

When to use =default vs =delete

To my understand these semantics are used only with the copy constructor, moving constructor, copy assignment, moving assignment, and the destructor. Using = delete is for prohibiting the use of one of the functions, and that = default is used if you want to be explicit to the compiler on where to use the defaults for these functions.
What are the best practices when using these keywords while making a class? Or rather how do I keep mindful of these when developing a class?
For example, if I don't know whether I'll use one of these functions, is it better to prohibit it with delete or allow it and use default?
Good question.
Also important: Where to use = default and = delete.
I have somewhat controversial advice on this. It contradicts what we all learned (including myself) for C++98/03.
Start your class declaration with your data members:
class MyClass
{
std::unique_ptr<OtherClass> ptr_;
std::string name_;
std::vector<double> data_;
// ...
};
Then, as close as is practical, list all of the six special members that you want to explicitly declare, and in a predictable order (and don't list the ones you want the compiler to handle). The order I prefer is:
destructor // this tells me the very most important things about this class.
default constructor
copy constructor // I like to see my copy members together
copy assignment operator
move constructor // I like to see my move members together
move assignment operator
The reason for this order is:
Whatever special members you default, the reader is more likely to understand what the defaults do if they know what the data members are.
By listing the special members in a consistent place near the top, and in a consistent order, the reader is more likely to quickly realize which special members are not explicitly declared &dash; and thus either implicitly declared, or not do not exist at all.
Typically both copy members (constructor and assignment) are similar. Either both will
be implicitly defaulted or deleted, explicitly defaulted or deleted, or explicitly supplied. It is nice to confirm this in two lines of code right next to each other.
Typically both move members (constructor and assignment) are similar...
For example:
class MyClass
{
std::unique_ptr<OtherClass> ptr_;
std::string name_;
std::vector<double> data_;
public:
MyClass() = default;
MyClass(const MyClass& other);
MyClass& operator=(const MyClass& other);
MyClass(MyClass&&) = default;
MyClass& operator=(MyClass&&) = default;
// Other constructors...
// Other public member functions
// friend functions
// friend types
// private member functions
// ...
};
Knowing the convention, one can quickly see, without having to examine the entire class declaration that ~MyClass() is implicitly defaulted, and with the data members nearby, it is easy to see what that compiler-declared and supplied destructor does.
Next we can see that MyClass has an explicitly defaulted default constructor, and with the data members declared nearby, it is easy to see what that compiler-supplied default constructor does. It is also easy to see why the default constructor has been explicitly declared: Because we need a user-defined copy constructor, and that would inhibit a compiler-supplied default constructor if not explicitly defaulted.
Next we see that there is a user-supplied copy constructor and copy assignment operator. Why? Well, with the data members nearby, it is easy to speculate that perhaps a deep-copy of the unique_ptr ptr_ is needed. We can't know that for sure of course without inspecting the definition of the copy members. But even without having those definitions handy, we are already pretty well informed.
With user-declared copy members, move members would be implicitly not declared if we did nothing. But here we easily see (because everything is predictably grouped and ordered at the top of the MyClass declaration) that we have explicitly defaulted move members. And again, because the data members are nearby, we can immediately see what these compiler-supplied move members will do.
In summary, we don't yet have a clue exactly what MyClass does and what role it will play in this program. However even lacking that knowledge, we already know a great deal about MyClass.
We know MyClass:
Holds a uniquely owning pointer to some (probably polymorphic) OtherClass.
Holds a string serving as a name.
Holds a bunch of doubles severing as some kind of data.
Will properly destruct itself without leaking anything.
Will default construct itself with a null ptr_, empty name_ and data_.
Will copy itself, not positive exactly how, but there is a likely algorithm we can easily check elsewhere.
Will efficiently (and correctly) move itself by moving each of the three data members.
That's a lot to know within 10 or so lines of code. And we didn't have to go hunting through hundreds of lines of code that I'm sure are needed for a proper implementation of MyClass to learn all this: because it was all at the top and in a predictable order.
One might want to tweak this recipe say to place nested types prior to the data members so that the data members can be declared in terms of the nested types. However the spirit of this recommendation is to declare the private data members, and special members, both as close to the top as practical, and as close to each other as practical. This runs contrary to advice given in the past (probably even by myself), that private data members are an implementation detail, not important enough to be at the top of the class declaration.
But in hindsight (hindsight is always 20/20), private data members, even though being inaccessible to distant code (which is a good thing) do dictate and describe the fundamental behaviors of a type when any of its special members are compiler-supplied.
And knowing what the special members of a class do, is one of the most important aspects of understanding any type.
Is it destructible?
Is it default constructible?
Is it copyable?
Is it movable?
Does it have value semantics or reference semantics?
Every type has answers to these questions, and it is best to get these questions & answers out of the way ASAP. Then you can more easily concentrate on what makes this type different from every other type.
Also, using =default instead of a hand-rolled one keeps the POD nature of the class, as it is described here in detail: Default constructors and POD
You often see = default when you are trying to maintain the rule of 5 to ensure the special member functions behave as you intend them to, and so that the reader of the class can see that you did consider how you wanted that function to behave.
You can use = delete if you intent to make something non-copyable or non-movable, for example. Though I have also seen people delete an inherited function if they do not want that specific derived class to have that function, though I'm not a huge fan of that since it tends to point towards poor architecture/design.

Which is the difference between declaring a constructor private and =delete?

For example, I want to declare a class but I want the client to not be able to use the copy constructor (or copy assignment operator)
Both of the following two does not allow the use of the copy constructor:
1.
class Track
{
public:
Track(){};
~Track(){};
private:
Track(const Track&){};
};
2.
class Track
{
public:
Track(){};
~Track(){};
Track(const Track&)=delete;
};
Is one of these ways "more correct" than the other or are equal? Is there any side-effect?
//Does not compile with both the above ways
int main()
{
Track l;
Track p(l);
}
Making it private is the "old" way of doing it. The constructor still exists, but it is private, and can only be invoked from within another class member function.
= delete deletes the constructor. It is not generated by the compiler, and it simply will not exist.
So most likely, = delete is what you want. (although with the caveat that not all compilers support this syntax yet, so if portability is a concern...)
Declaring a copy constructor private still allows member functions of the Track class to copy-construct instances of that class, while making it deleted simply forbids copy-constructing that object.
In C++11, deleting a copy constructor is the right way to express the fact that a class is non-copyable (unless of course it makes sense for you to let member functions of Track, or friends of Track, to copy-construct Track objects).
Making a constructor private was basically a "hack" in the old C++, since it was the only way to prevent users from using them. The ability to delete special member functions was only introduced in C++11, and it's the better and more idiomatic way to say that a class cannot be copied. since it is explicit about the intention.
Private constructors have other uses other than forbidding their use entirely (e.g. they may be called by static class member functions). So just making a constructor private doesn't communicate the intention very well, and the resulting error is not very clear, either.
Your first solution conveys to the reader that the copy-constructor is private and is not to be used.
Your second solution is only valid in C++11. Because of this, I'd say the more portable and readable implementation would be your first, using the private-property.
In the first case, you are essentially declaring a private copy constructor and then not providing any implementation. By declaring them private, non-members cannot copy it.
In the second case, the syntax forbids a copy being made. This is C++ native.
The major difference as a programmer is readability and understanding the code. The first case is redundant, why declare the copy constructor, make it private, and not implement it. The client has to infer a lot here.
You can just use "= delete" and clearly imply what you're trying to do.
Your first approach doesn't prevent the class itself from copying itself. The traditional way to solve this is to declare the copy-constructor private and to leave it unimplemented.
An issue with that, however, is that the intent might not be obvious. Someone reading the code might not understand why an orphaned declaration exists and might mistakenly remove it. Comments can help, as would privately inheriting from boost::noncopyable if Boost is available to you.
The second approach makes the intent obvious and is what you should prefer if you can use C++11.
If you are on C++11, use delete. The reason is that it makes the call explicit and the intent clear. You could still accidentally use a private constructor (e.g. in a restricted set of scopes), but the compiler will forbid you from ever using a deleted constructor.
One issue of the private constructor is that the class and friends can still use it -- this results not in access errors but link errors, which can be hard to trace back to the callsite.
If your necessary toolchains do not support deleted constructors (= delete), you should not define it (as seen in your question) -- only declare it and leave it undefined, e.g.: private: \n Track(const Track&);

Controlling instantiation and member variables in C++

From what I understand, when you create a C++ class, you implicitly have a default no argument constructor, a default copy constructor, and a default assignment operator.
If I want to be sure that I am alerted every time an instance of my object is created, or my object is mutated (e.g. through assignment), are these the only methods/constructors I have to worry about, given I keep all of my fields private?
If everything else in your class is private, yes.
Though do keep in mind that, if other people might have their hands in this code, unexpected modification might end up occurring in the private methods as well. So you might want to keep an eye on them too.
If the data members of your class are modified by an attack or a pointer manipulation error, you won't get alerted. Not sure if that was part of the question or not.

Why is a non-default constructor NOT considered in the Rule of Three?

The rule of three (also known as the Law of The Big Three or The Big Three) is a rule of thumb in C++ that claims that if a class defines one of the following it should probably explicitly define all three: destructor, copy constructor, copy assignment operator.
Why is a non-default constructor not considered as one of them? When there is any resource managed in the class, programmer has to define a non-default constructor anyway.
Why is a non-default constructor not considered as one of them? When there is any resource managed in the class, programmer has to define a non-default constructor anyway.
That is not necessarily true. The constructor might not aquire any resource. Other function(s) might aquire them as well. In fact, there can be many functions (including the constructor(s) themselves) which might aquire resources. For example, in case of std::vector<T>, it is resize() and reserve() which aquire resources. So think of constructor(s) just like other function(s) which might aquire resources.
The idea of this rule is that when you make a copy, the default-copy code generated by the compiler wouldn't work. Hence you need to write the copy-semantic yourself. And since the class manages resources (it doesn't matter which function(s) aquire it), the destructor must release it, because the destructor is guaranteed to be executed, for a fully constructed object. Hence you've to define the destructor as well. And in C++11, you've to implement move-semantics as well. The logical argument for move-semantic is same as that of copy-semantics, except that in move semantic, you changed the source as well. Move-semantic is much like organ-donor; when you give your organ to other, you don't own it anymore.
That's not what the rule of three is about.
Any class that manages resources will have that destructor, and hence the rule of three applies anyway. The point is that you don't absolutely need non-default constructors, but you do need the others (copy constructor / assignment operator).
At least it used to be vital for e.g. elements in standard containers.
Now with move semantics (c++11), things are starting to shift a bit. Will there be a rule of 5? I don't know how it will pan out in terms of 'best practices' and 'rules of thumb'.
In fact one could state a variation of the Rule of Three already: a class that defines a destructor should also define a copy/move constructor and copy/move assignment operator. AND if a copy constructor is defined, a copy assignment operator should also be defined. AND if a move constructor is defined, a move assignment operator should also be defined.
This is going to be my rule of thumb for a while, anyways.
If you aquire any resources (eg with new) you are quite right, but it is assumed that you don't forget to release the resources in the destructor. Once you created the destructor the rule of three kicks in and you should define all three.
However, if for example you only have some member variables in your class that you initialize with copy semantics you don't need the destructor and the rule doesn't apply.
Defining a non-default constructor doesn't automatically mean you need a destructor etc - you may just be using that constructor as a convenience to fill in a POD type.
That said, the same applies to default constructors.
Basically, the "do you need the big three?" is triggered when the class will manage a resource. You still might not need a default constructor, but you do need a constructor to set up a valid initial state.
That newly-constructed state may not own an instance of the resource yet, but if it doesn't, then it must know that it doesn't (e.g. have a null pointer).
However, the big three are also used implicitly in a lot of cases. Temporaries, for example, are default-constructed. One reason you would need a non-default constructor is simply to block the implicit default constructor from being provided and used.
So one reason to define all three at once is to ensure that your code (including that provided implicitly by the compiler) remains sane.
Almost always, if you're managing a resource, you will have a default constructor, so that's why the rule mentions that - but so long as you define some kind of constructor, you should be OK.

Why is the Compiler-Emitted C++ Default Constructor "bad"?

Could someone please explain what is meant by the following?
You must define a default constructor if your class defines member variables and has no other constructors. Otherwise the compiler will do it for you, badly.
What are they referring to as "badly"?
From the expansion of that link:
"The reason for this is that if you
have no other constructors and do not
define a default constructor, the
compiler will generate one for you.
This compiler generated constructor
may not initialize your object
sensibly."
Might refer to how new T and new T() differ when there is no ctor provided.
It's good to be sure that the object is created in a known state. Primitive variables won't be set to zero by default, so you could end up with subtle bugs that don't always show up. By initializing the member variables to sensible variables, everything is much more predictable.
The only problem with the default constructor is that it initializes only what the compiler thinks must be initialized, and not what you may think needs to be initialized. Basically, that means that it will invoke initializers for objects with default initializers. It won't set pointers or simple types like int to sane values, etc. If that is sufficient, then the default constructor is not 'bad'. When it is insufficient, it is a bug (in your code) that you did not define the necessary default constructor with the correct initialization.
Take the Google style guide with a grain of salt -- or maybe a truckload of salt.
It is true that the compiler-generated default constructor won't necessarily initialize members that are of built-in types in a meaningful fashion. If you want that done, then yes, its failure to do that is bad. OTOH, if you don't want that done, then its doing it could be somewhat bad (wasteful) as well.
Bottom line: there are times to write your own default ctor, but they tend toward the exception, not the rule. Although there are simple rules of thumb to cover a lot of cases in C++ and will prevent a lot of problems, this really isn't one of them -- here you pretty much do need to know what the compiler-generated ctor will do, and what you want different if you're going to write your own.
In Debug build most compilers fill uninitialized space with some magic values, so that debugging is reliable. And providing custom constructor prevents certain POD optimizations.
In fact, it's a guideline just to make sure people does explicitely make the statement of what is an invalid or default state of any object.
That way, no surprise when reading the code, compared to the actual execution.
However, think that it's a company guideline, that is used to make sure everyone does follow the same rules, that's not a you-must-follow-it-because-google-does-it.
In fact, if you manage to make all your member objects being in valid state when default constructed, or force you to set a constructor, then there is no good reason for such a guideline.
If you have any primitive types as member variables (eg. int, float), then the default ctor will not initialize them. member variables that are a class type will have their default ctor's invoked.
Prefer member initializer lists, so your user supplied ctor may be empty:
class Foo {
int bar;
float baz;
Foo(): bar(0), baz(0.0f) { /* empty ctor body */ }
};
It won't set integers to 0 or pointers to null. It will run default constructors on object of types with constructors.
Some people would call it 'not sensible'.
It just seems a too simplified version of the rules of 3, you should either define yourself or leave the compiler version of
the copy constructor
the assignment operator
the destructor
(Note that by defining yourself a copy constructor, the compiler won't define a default constructor).
The default constructor built by the compiler does 'nothing', it will not even zero the memory occupied by the object