9

We have the following method to test if our structure is a POD or not. It always returns true:

bool podTest() {
  struct podTest {
    int count;
    int x[];
  };

  return std::is_pod<podTest>::value;  //Always returns true
}

So far so good. Now we make one change and delete the copy constructor:

bool podTest() {
  struct podTest {
    podTest(const podTest&) = delete;
    int count;
    int x[];
  };

  return std::is_pod<podTest>::value;  //Always returns false
}

This always returns false. After reading over the definition of is_pod I am still struggling to understand what requirement it violates. What am I missing?

This is being compiled on godbolt using gcc 6.1, with -std=c++14

Barry
  • 286,269
  • 29
  • 621
  • 977
Chuu
  • 4,301
  • 2
  • 28
  • 54
  • 3
    At a guess because you are saying the struct cannot be copied, but one of the qualities of POD types is that they are always copyable. –  Feb 06 '17 at 23:09
  • 1
    @NeilButterworth: One of the requirements of POD types is, that they are **trivially** copyable. – IInspectable Feb 06 '17 at 23:17
  • 1
    Oddly enough, `std::is_trivially_copyable::value` returns true, so there must be some other violation of POD requirements. Certainly `int x[];` should be removed. Unless I'm mistaken, flexible array bounds aren't part of C++14. – IInspectable Feb 06 '17 at 23:28
  • 1
    @IInspectable libstdc++ implements `std::is_pod` with a compiler hook it seems, not via the `std::is_trivially_copyable`. libc++ also uses the compiler hook if available, but its fallback implementation is wrong too because Trivially Copyable is not the same as (Trivially Copy Constructible && Trivially Copy Assignable), which is what they check for. – Baum mit Augen Feb 06 '17 at 23:41

2 Answers2

9

Aha!

From [class]:

A POD struct is a non-union class that is both a trivial class and a standard-layout class

where a trivial class is:

A trivial class is a class that is trivially copyable and has one or more default constructors (12.1), all of which are either trivial or deleted and at least one of which is not deleted.

But in [class.copy]:

If there is no user-declared constructor for class X, a non-explicit constructor having no parameters is implicitly declared as defaulted (8.4).

Your podTest, when you explicitly deleted the copy constructor, has no default constructor. So it's not a trivial class, so it's not a POD. If you add in:

podTest() = default;

Then it'll become a POD again.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • So in this case, a class without a copy constructor can still be copied with memcpy()! – Sjoerd Feb 07 '17 at 08:29
  • If there are two default ctors, with one deleted and one not. Is there not an ambiguity if you try to create an object of the class? I wonder about the reason for this "at least one non-deleted" rule. – Johannes Schaub - litb Feb 07 '17 at 16:17
  • @JohannesSchaub-litb It's possible to be non-ambiguous: `struct X { X() = default; template X(Args&&...) = delete; }; X x;` – Barry Feb 07 '17 at 16:20
  • @Barry correct, but the text makes even the ambiguous cases PODs. And if you placed the `= delete` onto the non-template and didn't delete the other template default-ctor, it would still have marked it as a POD. – Johannes Schaub - litb Feb 07 '17 at 16:31
  • @JohannesSchaub-litb Yeah I don't know. It seems like a very specific wording choice. – Barry Feb 07 '17 at 16:43
2

Because deleted copy constructors are allowed for POD types only after C++14. I would assume, you are compiling your code in C++11 mode.

SergeyA
  • 61,605
  • 5
  • 78
  • 137
  • The `struct` above is trivially copyable in both C++11 and C++14, and according to cppr, that's all the copy semantics we need for POD. – Baum mit Augen Feb 06 '17 at 23:09
  • 3
    It's so strange to me that a noncopyable type can be POD. I thought POD types were supposed to have the same behaviour in C and C++. – Brian Bi Feb 06 '17 at 23:09
  • @BaummitAugen, is this page: http://en.cppreference.com/w/cpp/concept/TriviallyCopyable wrong than? – SergeyA Feb 06 '17 at 23:09
  • @SergeyA Probably. https://stackoverflow.com/questions/29759441/is-a-class-with-deleted-copy-constructor-trivially-copyable Edit: No, I don't think so. Looks a little inprecise at most. – Baum mit Augen Feb 06 '17 at 23:10
  • @BaummitAugen, i think, this answer is outdated..? – SergeyA Feb 06 '17 at 23:11
  • @SergeyA You mean in the question I linked? That handles both C++11 and C++14, so I don't think so. – Baum mit Augen Feb 06 '17 at 23:13
  • I've edited the question to specify the compiler/language version since it appears to be relevant. – Chuu Feb 06 '17 at 23:20
  • Actually, I cannot find the update from the CWG fix T.C. cites in N4141; the rules there seem to match C++11. So either there is a major difference between N4141 or the entire C++14 part on Trivial Types, including trivially copyable, is just wrong. – Baum mit Augen Feb 06 '17 at 23:33
  • 1
    Had to dv, Barry found the correct reason, proving this answer wrong. – Baum mit Augen Feb 06 '17 at 23:49
  • 1
    @Brian `struct X { X(X const&) = delete; }` is trivially copyable. I love C++. Then again, you can't really have a noncopyable type in C right? – Barry Feb 06 '17 at 23:53
  • @Barry And indeed, you are allowed to memcpy struct X, as it is trivially copyable, even when the copy constructor is deleted. It doesn't feel right, though. – Sjoerd Feb 07 '17 at 08:27