4

I have a class like so:

Snippet 1:

struct B
{
    int member;
    // more complex members e.g. arrays of structs etc
};

This class is used in the code assuming it is a C style struct (e.g. used in memcpy, memset etc)

As part of good programming principles, I am contemplating modifying B like so:

Snippet 2

struct B 
{
    B() {}
    int member;
    // more complex members e.g. arrays of structs etc
};

Here is my understanding. Please correct if I got this wrong a. Snippet 1 defines B which is a POD whereas Snippet 2 defines B which is not a POD, AND b. In Snippet 2, B can still be legitimately used for C style uses such as memset and memcpy

  1. std::is_pod : false
  2. std::is_trivial : false
  3. std::is_trivially_copyable : true
  4. std::is_trivial : false

Extending, I would also follow the rule of Big 3 (or perhaps Big 5), I would add copy assignment as well as copy constructor.

Snippet 3:

struct B
{
    B() {}
    ~B(){}
    B& operator=(B &){ return *this; }
    B(B const &r){}
    int member;

    // more complex members e.g. arrays of structs etc
};

Here is my understanding. Please correct if I got this wrong a. In Snippet 3, B can now no longer be legitimately used for C style uses such as memset and memcpy

  1. std::is_pod : false
  2. std::is_trivial : false
  3. std::is_trivially_copyable : false
  4. std::is_trivial : false

I need understanding on the effect of adding various members to B in Snippet 2 and Snippet 3 on C style uses of B.

Is the C Style use of a class really based on is_trivially_copyable or on is_trivial (which is more restrictive)?

Reading $3.9/2 indicates to me that in C++11 "is_trivially_copyable" is really the determining criteria. Some old C++ books (C++ in a nutshell e.g.) however indicate the criteria is about POD vs non POD and I understand that C++11 rules have changed since.

Petes response seems to indicate that trivial-ness is the necessary criteria

Jonas
  • 121,568
  • 97
  • 310
  • 388
user3701522
  • 307
  • 3
  • 12

1 Answers1

2

If your struct only contains POD data members, and is not responsible for managing any resources, such as dynamically allocated memory, there's absolutely no reason to define the destructor, copy constructor and assignment operators. At most I'd add a constructor to initialize the data members. And with C++11, this can be done trivially using non-static data member initializers.

struct B
{
    int member = 0; // this will initialize the data member to 0
};

You could also add a constructor that takes an int and allows you to initialize member to any desired value. In that case

struct B
{
    int member;
    explicit B(int member = 0) : member(member) {}
};

Both of these changes will leave your class trivially copyable (9/6) and standard layout (9/7), which means you'll be able to use them with C-style functions.


From the discussion in the comments, it seems you're not necessarily interested in being able to initialize all data members, but still want to provide a default constructor.

struct B 
{
    B() {}
    int member;
    // more complex members e.g. arrays of structs etc
};

This is a bad idea because it doesn't add anything useful to the class, and makes it non-trivial because it now has a non-trivial default constructor. If you really want to define a default constructor, you should explicitly default it instead.

struct B 
{
    B() = default;
    int member;
    // more complex members e.g. arrays of structs etc
};

This leaves the class trivial, and standard layout, allowing you to use it with C style functions.

Praetorian
  • 106,671
  • 19
  • 240
  • 328
  • That was just a representative C style class. I will modify my post accordingly. Sorry about that – user3701522 Jun 08 '14 at 04:42
  • also the in class initializer makes the class a non POD. Are non PODs eligible for C style usage? – user3701522 Jun 08 '14 at 04:44
  • How much state is in general immaterial to the object semantics. – Potatoswatter Jun 08 '14 at 04:46
  • The addition of a user defined constructor makes a class non POD, once again – user3701522 Jun 08 '14 at 04:47
  • @user3701522 Yes, see the last sentence – Praetorian Jun 08 '14 at 04:47
  • @Potatoswatter I'm not sure what that means – Praetorian Jun 08 '14 at 04:47
  • "If your class truly contains just a single int member there's absolutely no reason to define the destructor, copy constructor and assignment operators." — Whether there's zero, one, or two `int`s has no bearing on what other members might be useful. – Potatoswatter Jun 08 '14 at 04:49
  • @Praetorian: I agree, but as I mentioned in post, I would naturally extend this class for good OO design by adding copy constructor, assignment, destructor etc. That makes the class 'non trivially copyable', but 'standard layout'. Now does that permit C style usage? – user3701522 Jun 08 '14 at 04:50
  • 2
    @user3701522 I think the real answer to your question is that adding boilerplate never inherently improves design. Note that C++11 adds the alternative of `= default` definitions for all the special member functions, which allows explicitness but provides the same behavior as if you used the implicit definitions. You could then "define" all the special member functions and still have a POD, aggregate, whatever, class. – Potatoswatter Jun 08 '14 at 04:52
  • @Potatoswatter Fair enough, that wasn't the best choice of words in hindsight – Praetorian Jun 08 '14 at 04:53
  • 2
    @user3701522 What Potatoswatter said, there's no need to add a bunch of boilerplate to a class that only deals with POD types. The compiler generated copy constructor/assignment operator etc. are sufficient. – Praetorian Jun 08 '14 at 04:54
  • @Potatoswatter: I can see your point. request you to crystallize it in a separate answer, please – user3701522 Jun 08 '14 at 04:56
  • @Praetorian: So, my understanding is to stick to Snippet 2 but not add copy constructor/copy assignment. But, that way the class still becomes POD. So back to my original question, is C style usage of POD classes fine? – user3701522 Jun 08 '14 at 05:01
  • It appears that standard_layout is a necessary condition for C style usage. But is it a sufficient condition as well? – user3701522 Jun 08 '14 at 05:28
  • @user3701522 That's the only one the standard calls out, so I'd say yes. Also note that with the `default`ed constructor your class is now a POD. That's pretty much the strongest guarantee you can get. – Praetorian Jun 08 '14 at 05:40
  • The Standard calls out for is_trivially_copyable in 3.9/2. Can you please point me to where it calls out is_standard_layout? – user3701522 Jun 08 '14 at 06:02
  • @user3701522 9/9 — Standard-layout classes are useful for communicating with code written in other programming languages. Their layout is specified in 9.2. – Praetorian Jun 08 '14 at 06:12
  • You can `memcpy` precisely trivially copyable classes. Being standard layout or not has no bearing. You can do C-style inheritance (or in general C-style layout tricks) precisely with standard-layout classes. Being trivially copyable or not has no bearing. – n. m. could be an AI Jan 03 '21 at 15:36