1

In older versions of C++ if one wanted to prevent copying of a class object they would typically declare the Copy Constructor and operator=() in the private section of a class as such:

class Foo {
public:
    Foo(){} // Default
    ~Foo(){} // Default

private:
    Foo( const Foo& c ); // not implemented
    Foo& operator=( const Foo& c ); // not implemented
};

Which is pretty straight forward. Now with newer versions of C++ we can now do this instead.

class Foo {
public:
    Foo() = default;
    ~Foo() = default;
private:
    Foo( const Foo& c ) = delete;
    Foo& operator=( const Foo& c ) = delete;
};

My question then becomes this: With the modern approach of declaring these as deleted functions, does it matter or make any difference if they are defined in the public, protected or private sections of its class?


For example is there any difference between the one above and this:

class Foo {
public:
    Foo() = default;
    ~Foo() = default;
    Foo( const Foo& c ) = delete;
    Foo& operator=( const Foo& c ) = delete;
};

Edit:

I have accepted ShadowRanger's answer due to their explanation with examples as well as providing a link to this Q/A that clearly explains the recommendations and why...

It has come to my attention that in the first example when they are declared private you will get additional compiler errors on top of the already existing compiler errors that are already being generated when they are being declared as public.

Francis Cugler
  • 7,788
  • 2
  • 28
  • 59

4 Answers4

5

It has been recommended that the deleted function be public if only to simplify the error messages. For example, on gcc, the error messages are more verbose when the deleted copy constructor is declared private, without really being more informative, e.g. on g++ 7, you'll get this error either way:

deleted_copy.cpp:5:10: error: use of deleted function ‘A::A(const A&)’
    A b = a;
          ^
In file included from deleted_copy.cpp:1:0:
deleted_copy.h:6:5: note: declared here
     A(const A&) = delete;
     ^

But if the copy constructor is private, you'll also get (above the error given above; the error about the copy constructor being deleted is last):

deleted_copy.cpp: In function ‘int main()’:
deleted_copy.cpp:5:10: error: ‘A::A(const A&)’ is private within this context
    A b = a;
          ^
In file included from deleted_copy.cpp:1:0:
deleted_copy.h:6:5: note: declared private here
     A(const A&) = delete;
     ^

In both cases, deleted_copy.cpp is:

#include "deleted_copy.h"

int main() {
   A a;
   A b = a;
}

and my deleted_copy.h was:

class A
{
public:
    A() = default;
private:
    A(const A&) = delete;
};

with the private line commented out when testing how it behaves as public.

ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • Thank you for a clarifying answer with examples. I don't typically use clang or gcc; mostly use visual studio, however it is very good to know. – Francis Cugler Jan 24 '18 at 00:37
  • Also I did search stack for a similar question but couldn't find any until you provided one with the link at the top of your answer, thank you for the link. – Francis Cugler Jan 24 '18 at 00:39
  • Okay I found out that I was missing the term `modifier` for the delete key word, when doing the searches. After reading the Q/A from the link you provided that answered other similar questions that pertain more with the `compiler` & `linker`, yet still fits with this question about the difference between declaring them `public` or `private`. Due to the better understanding of what is recommended I'll have to accept your answer over the others. – Francis Cugler Jan 24 '18 at 00:51
3

No, it does not matter. A deleted constructor will only cause compilation failure after it has been picked by overload resolution. Meaning that if you'd have deleted private constructors which you would then try to use outside of the class you'd get an access error before you'd get a deleted constructor error.

Either way, no matter what scope the deleted constructor is, any call to it will end in a compilation error.

Hatted Rooster
  • 35,759
  • 6
  • 62
  • 122
  • Thank you for the quick answer, I didn't think it did, but don't like assuming just wanted clarification. It's more towards when designing a class having the perspective of how the `compiler` treats it. – Francis Cugler Jan 23 '18 at 23:46
1

It does not matter for two reasons:

First, delete avoids implicit generation of the copy constructor, so the copy constructor is not generated at all, neither in a private nor in a public or whatsoever section.

Second, an implicitly-declared or defaulted copy constructor for class T is defined as deleted if T has direct or virtual base class that cannot be copied (has deleted, inaccessible, or ambiguous copy constructors);

So a deleted copy constructor is simply as if there is no copy constructor, and due to above definition, this cannot be "repaired" in subclasses.

Stephan Lechner
  • 34,891
  • 4
  • 35
  • 58
  • 1
    "*the copy constructor is not generated at all*" - well, almost. It still exists, it just doesn't have any body code generated for it. But overload resolution and such can still find a `deleted` copy constructor, it will just emit an error if there are no other candidates. – Remy Lebeau Jan 23 '18 at 23:57
1

It makes no difference as far as how the class can be used or not.

But it can make a difference in compiler diagnostic messages. Using g++ version 5.4.0, I get both compiler errors about accessing a private member and errors about using a deleted function when trying to use a member that is both private and deleted. On the other hand, a couple of different clang++ versions seem to be smart enough to just show the message about the function being deleted and ignore the less relevant private access detail.

So I prefer to declare these members as public. The fact that the function is deleted is really what you want to show up on an invalid use, and if a compiler also complains about private access, that's just extra noise. But also, and maybe more important, the fact that a class is not copyable and/or copy assignable is a key property of the class and would likely be relevant to a human reading just the public: section.

aschepler
  • 70,891
  • 9
  • 107
  • 161