2
struct A
{
  int i;
};

struct B
{
 B(){} 
 int i;
}

Hi,all

I know "POD means Plain Old Data type which by definition cannot have user-defined constructor". But I can't understand why this rule is effective when "definition have an user-defined default-con".

There is no difference of their memory layout.Why type A is POD,but not B?

Jonas
  • 121,568
  • 97
  • 310
  • 388
Leonhart Squall
  • 810
  • 1
  • 7
  • 15
  • Add a language flag. C++, right? – doctorlove Jul 17 '13 at 08:29
  • 2
    possible duplicate of [What are POD types in C++?](http://stackoverflow.com/questions/146452/what-are-pod-types-in-c) – Macmade Jul 17 '13 at 08:35
  • Because the language says so? POD means the state is expressed entirely by the members, but having a user-defined constructor means there's additional state in the logic of the constructor. – Kerrek SB Jul 17 '13 at 08:57

3 Answers3

8

The reason is simple. Once you define a constructor (any constructor), the language assumes that the class needs some sort of initialization; that just copying the bits in its image won't be sufficient to create a new instance. And one of the important characteristics of PODs is that they can be memcpy'ed.

In sum, the compiler does not look at the contents of a class to determine whether it is POD or not (except to see if any of the members are PODS). It looks at whether you've defined anything special which might affect the initialization, assignment or destruction of those members.

James Kanze
  • 150,581
  • 18
  • 184
  • 329
  • 5
    A "trivially copyable" class in c++11 can be memcpy'd, and is allowed to have user-provided constructors. – interjay Jul 17 '13 at 09:12
  • @interjay About "allowed to have user-provided constructors".Do you mean the user-provided constructors are using =default? – Leonhart Squall Jul 17 '13 at 10:23
  • @LeonhartSquall: No, a trivially copyable class can have any constructor provided by the user (with non-default behavior) except for copy and move constructors. – interjay Jul 17 '13 at 10:38
  • @James Kanze When compiler cannot look at the contents it is really impossible to determine a class weather a POD type.But I think the compiler can obtain this context usually as you say "to see if any of the members are PODS".And I think this is a correct way instead of by finding a class weather having any constructor. – Leonhart Squall Jul 17 '13 at 10:40
  • @interjay http://en.cppreference.com/w/cpp/concept/TriviallyCopyable note one writes "Other than the other requirements, trivial constructor, assignment and destructor must be defined implicitly (not user-provided)". – Leonhart Squall Jul 17 '13 at 10:48
  • 1
    @LeonhartSquall That sentence is written quite confusingly, and I assume it refers to the copy/move constructors mentioned above. It seems quite redundant anyway because a trivial constructor/destructor is by definition not user-provided. In any case, the standard (9p6) only mentions copy and move constructors, copy/move assignment operators, and the destructor. – interjay Jul 17 '13 at 11:01
  • @LeonhartSquall Consider a typical implementation of `std::string` or `std::vector`. All of the members will have POD type, but the class itself is definitely not a POD. The constructors, assignment operator, etc. define a number of invariants on the POD data, which must be maintained. – James Kanze Jul 17 '13 at 11:44
  • @interjay If you're referring to the change in the text of §3.9/3, this is clearly an error in the standard, since it can only be true up to a point: if the class has a non-trivial destructor or assignment operator, the `memcpy` will not work. (Of course, it's hard to imagine a class which needs a non-trivial destructor or assignment operator, but can use a trivial copy constructor.) – James Kanze Jul 17 '13 at 11:51
  • @JamesKanze I don't know what change in the text you are referring to. If a class has a non-trivial destructor or assignment operator then it isn't trivially copyable, and 3.9/3 doesn't apply. See 9/6 for requirements of a trivially copyable class. – interjay Jul 17 '13 at 12:00
  • @James Kanze So my understanding is: compiler will treat this class as 'C++ style' not POD type when the compiler meet a default constructor, becuase the compiler thinks the default constructor must do some special initialize work that belongs to C++, even though the default constructor doesn't do anything and actually the type of very member in the class is POD.Is my understanding correct? – Leonhart Squall Jul 19 '13 at 06:28
  • @LeonhartSquall Yes, C++11 adds additional categories. – James Kanze Jul 19 '13 at 07:53
3

The concept of POD has been split into trivial and standardy-layout concepts. You can query those properties through the standard type traits.

Class B is not POD because it is not trivial. It is not trivial because it has a user-provided default constructor. Either omit that or use the new C++11 =default syntax.

#include <type_traits>
#include <iostream>
#include <ios>

struct A
{
  int i;
};

struct B
{
 B(){} 
 int i;
};

struct C
{
 C() = default;
 int i;
};

int main()
{
    std::cout << std::boolalpha << std::is_pod<A>::value << " ";
    std::cout << std::boolalpha << std::is_trivial<A>::value << " ";
    std::cout << std::boolalpha << std::is_standard_layout<A>::value << "\n";

    std::cout << std::boolalpha << std::is_pod<B>::value << " ";
    std::cout << std::boolalpha << std::is_trivial<B>::value << " ";
    std::cout << std::boolalpha << std::is_standard_layout<B>::value << "\n";

    std::cout << std::boolalpha << std::is_pod<C>::value << " ";
    std::cout << std::boolalpha << std::is_trivial<C>::value << " ";
    std::cout << std::boolalpha << std::is_standard_layout<C>::value << "\n";
}

Online output:

true true true
false false true
true true true
Community
  • 1
  • 1
TemplateRex
  • 69,038
  • 19
  • 164
  • 304
1

PODs allow the compiler to do certain optimizations. As a rule of thumb, a type is POD if the compiler is allowed to treat the struct the same way as a C-compiler would.

In particular, when initializing a POD struct, the compiler just needs to reserve memory of the appropriate size, it does not need to worry about initialization. Initialization can be requested explicitly by the programmer, but it never happens implicitly as could be the case with a user-defined constructor.

For example, a user-defined default constructor might require the data to get initialized to 0. In general, the default constructor might even have arbitrary side effects that the compiler needs to consider.

ComicSansMS
  • 51,484
  • 14
  • 155
  • 166
  • What, illustratively, is the difference between `malloc`ing and `new`ing? Doesn't `new A()` do initialization? – Jonathan Wakely Jul 17 '13 at 09:09
  • 2
    @JonathanWakely `new` performs initialization (usually by calling a constructor), `malloc` does not. – ComicSansMS Jul 17 '13 at 09:24
  • `new A` doesn't do initialization if `A` is POD, but `new A()` does do initialization even if `A` is POD. My point is that your "analogy for illustrative purposes" isn't actually very illustrative, because I can "allocate memory for an array of POD structs" and still have the compiler initialize it. There are better ways to define PODs than a flawed analogy. – Jonathan Wakely Jul 17 '13 at 10:34
  • @JonathanWakely I see your point. I was trying to make clear what I meant with the malloc/new analogy, but apparently it was still not clear enough. Rephrased the question accordingly. – ComicSansMS Jul 17 '13 at 10:52